core_validation.cpp revision 3616276bb0053c612c0a8d223e81ae3808b1b2c4
14f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes/* Copyright (c) 2015-2017 The Khronos Group Inc.
24f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes * Copyright (c) 2015-2017 Valve Corporation
34f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes * Copyright (c) 2015-2017 LunarG, Inc.
44f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes * Copyright (C) 2015-2017 Google Inc.
55b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
643b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Licensed under the Apache License, Version 2.0 (the "License");
743b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * you may not use this file except in compliance with the License.
843b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * You may obtain a copy of the License at
95b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
1043b53e83705f02245da6ae61e31273866a35b833Jon Ashburn *     http://www.apache.org/licenses/LICENSE-2.0
115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
1243b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Unless required by applicable law or agreed to in writing, software
1343b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * distributed under the License is distributed on an "AS IS" BASIS,
1443b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1543b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * See the License for the specific language governing permissions and
1643b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * limitations under the License.
175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Cody Northrop <cnorthrop@google.com>
195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Michael Lentine <mlentine@google.com>
205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Tobin Ehlis <tobine@google.com>
215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Chia-I Wu <olv@google.com>
225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Chris Forbes <chrisf@ijw.co.nz>
235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Mark Lobodzinski <mark@lunarg.com>
245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Ian Elliott <ianelliott@google.com>
2560cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Dave Houlton <daveh@lunarg.com>
2660cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Dustin Graves <dustin@lunarg.com>
2760cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Jeremy Hayes <jeremy@lunarg.com>
2860cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Jon Ashburn <jon@lunarg.com>
2960cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Karl Schultz <karl@lunarg.com>
3060cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Mark Young <marky@lunarg.com>
3160cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Mike Schuchardt <mikes@lunarg.com>
3260cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Mike Weiblen <mikew@lunarg.com>
3360cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Tony Barbour <tony@LunarG.com>
345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis */
355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Allow use of STL min and max functions in Windows
375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#define NOMINMAX
385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3994c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <SPIRV/spirv.hpp>
4094c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <algorithm>
4194c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <assert.h>
4294c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <iostream>
4394c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <list>
4494c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <map>
45b9e992386a44404152747d66817a733aa127e281Jeremy Hayes#include <mutex>
4694c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <set>
4768d157d34807071526e5d78b3b3b68c5a4c6185fMark Lobodzinski#include <sstream>
485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <stdio.h>
495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <stdlib.h>
505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <string.h>
5194c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <string>
52dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes#include <tuple>
535770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus#include <inttypes.h>
545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_loader_platform.h"
565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_dispatch_table_helper.h"
5768d157d34807071526e5d78b3b3b68c5a4c6185fMark Lobodzinski#include "vk_enum_string_helper.h"
585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined(__GNUC__)
595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#pragma GCC diagnostic ignored "-Wwrite-strings"
605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined(__GNUC__)
625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#pragma GCC diagnostic warning "-Wwrite-strings"
635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "core_validation.h"
65c06c9b88f5f5bcc7033ba41d5547b048fa6015a4Mark Lobodzinski#include "buffer_validation.h"
665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_table.h"
675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_data.h"
685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_extension_utils.h"
695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_utils.h"
70b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes#include "spirv-tools/libspirv.h"
715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined __ANDROID__
735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <android/log.h>
745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "DS", __VA_ARGS__))
755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#else
76cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#define LOGCONSOLE(...)      \
77cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    {                        \
78cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        printf(__VA_ARGS__); \
79cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        printf("\n");        \
80c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
835770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus// TODO: remove on NDK update (r15 will probably have proper STL impl)
845770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus#ifdef __ANDROID__
855770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausnamespace std {
865770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
875770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraustemplate <typename T>
885770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstd::string to_string(T var) {
895770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::ostringstream ss;
905770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    ss << var;
915770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return ss.str();
925770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus}
935770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus}
945770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus#endif
955770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
96d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan// This intentionally includes a cpp file
97d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan#include "vk_safe_struct.cpp"
98d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan
99d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wunamespace core_validation {
100d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
1015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_map;
1025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_set;
1030c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::unique_ptr;
1040c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::vector;
1050c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::string;
1060c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::stringstream;
1070c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::max;
1085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// WSI Image Objects bypass usual Image Object creation methods.  A special Memory
1105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Object value will be used to identify them internally.
1115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkDeviceMemory MEMTRACKER_SWAP_CHAIN_IMAGE_KEY = (VkDeviceMemory)(-1);
112888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// 2nd special memory handle used to flag object as unbound from memory
113888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisstatic const VkDeviceMemory MEMORY_UNBOUND = VkDeviceMemory(~((uint64_t)(0)) - 1);
114b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
1152e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// A special value of (0xFFFFFFFF, 0xFFFFFFFF) indicates that the surface size will be determined
1162e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// by the extent of a swapchain targeting the surface.
1172e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madillstatic const uint32_t kSurfaceSizeFromSwapchain = 0xFFFFFFFFu;
1182e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill
1195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// fwd decls
1205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module;
1215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
122f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct instance_layer_data {
123d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkInstance instance = VK_NULL_HANDLE;
124d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    debug_report_data *report_data = nullptr;
1255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<VkDebugReportCallbackEXT> logging_callback;
1269172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkLayerInstanceDispatchTable dispatch_table;
1279172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes
128219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CALL_STATE vkEnumeratePhysicalDevicesState = UNCALLED;
129219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    uint32_t physical_devices_count = 0;
130b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    CALL_STATE vkEnumeratePhysicalDeviceGroupsState = UNCALLED;
131b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    uint32_t physical_device_groups_count = 0;
132219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CHECK_DISABLED disabled = {};
133219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
134f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    unordered_map<VkPhysicalDevice, PHYSICAL_DEVICE_STATE> physical_device_map;
135747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    unordered_map<VkSurfaceKHR, SURFACE_STATE> surface_map;
136747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
1370cf009a4e2a5c22e4645f343c7a998f188a22015Chris Forbes    InstanceExtensions extensions;
138f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes};
139f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes
140f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct layer_data {
141f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    debug_report_data *report_data = nullptr;
1424a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkLayerDispatchTable dispatch_table;
14394c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis
144a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski    DeviceExtensions extensions = {};
145cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    unordered_set<VkQueue> queues;  // All queues under given device
1465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Layer specific data
147d31a44af6da568692a73201825459689c9431867Tobin Ehlis    unordered_map<VkSampler, unique_ptr<SAMPLER_STATE>> samplerMap;
14879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis    unordered_map<VkImageView, unique_ptr<IMAGE_VIEW_STATE>> imageViewMap;
1491facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    unordered_map<VkImage, unique_ptr<IMAGE_STATE>> imageMap;
15039267c0c27b8f032f05a6747eb02d4508247fdc1Tobin Ehlis    unordered_map<VkBufferView, unique_ptr<BUFFER_VIEW_STATE>> bufferViewMap;
1515cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    unordered_map<VkBuffer, unique_ptr<BUFFER_STATE>> bufferMap;
1524c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    unordered_map<VkPipeline, PIPELINE_STATE *> pipelineMap;
1538d6a38de0389036581ada119e548180c614fe0efChris Forbes    unordered_map<VkCommandPool, COMMAND_POOL_NODE> commandPoolMap;
154a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE *> descriptorPoolMap;
155397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis    unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> setMap;
156cb9ce9e05b8e939d3da35c64997c70049877f4feTobin Ehlis    unordered_map<VkDescriptorSetLayout, cvdescriptorset::DescriptorSetLayout *> descriptorSetLayoutMap;
1575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
15857fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    unordered_map<VkDeviceMemory, unique_ptr<DEVICE_MEM_INFO>> memObjMap;
1595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkFence, FENCE_NODE> fenceMap;
16036c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    unordered_map<VkQueue, QUEUE_STATE> queueMap;
1614710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    unordered_map<VkEvent, EVENT_STATE> eventMap;
1625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<QueryObject, bool> queryToStateMap;
1635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
1645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
16572d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis    unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap;
166c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    unordered_map<VkFramebuffer, unique_ptr<FRAMEBUFFER_STATE>> frameBufferMap;
1675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap;
1685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
169127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    unordered_map<VkRenderPass, unique_ptr<RENDER_PASS_STATE>> renderPassMap;
170918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes    unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap;
1716246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    unordered_map<VkDescriptorUpdateTemplateKHR, unique_ptr<TEMPLATE_STATE>> desc_template_map;
17216a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes    unordered_map<VkSwapchainKHR, std::unique_ptr<SWAPCHAIN_NODE>> swapchainMap;
17307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
174d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkDevice device = VK_NULL_HANDLE;
175ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    VkPhysicalDevice physical_device = VK_NULL_HANDLE;
1765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    instance_layer_data *instance_data = nullptr;  // from device to enclosing instance
17807a464bd7fec9583f346b8c4b8d43c88d2e9ffa4Chris Forbes
179f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes    VkPhysicalDeviceFeatures enabled_features = {};
1805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Device specific data
181d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    PHYS_DEV_PROPERTIES_NODE phys_dev_properties = {};
182d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkPhysicalDeviceMemoryProperties phys_dev_mem_props = {};
183e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    VkPhysicalDeviceProperties phys_dev_props = {};
1845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
1855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
186b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis// TODO : Do we need to guard access to layer_data_map w/ lock?
187b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlisstatic unordered_map<void *, layer_data *> layer_data_map;
188f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic unordered_map<void *, instance_layer_data *> instance_layer_data_map;
189b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
190b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Youngstatic uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
191b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
192e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wustatic const VkLayerProperties global_layer = {
193f1ea418f193d10a8455cdf47e0eeeeb1f4d8b5bfJon Ashburn    "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
194e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu};
1955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
196cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class TCreateInfo>
197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskivoid ValidateLayerOrdering(const TCreateInfo &createInfo) {
1985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool foundLayer = false;
1995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) {
200e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu        if (!strcmp(createInfo.ppEnabledLayerNames[i], global_layer.layerName)) {
2015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            foundLayer = true;
2025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This has to be logged to console as we don't have a callback at this point.
2045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) {
205bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.", global_layer.layerName);
2065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Code imported from shader_checker
2115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *);
2125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words
2145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// without the caller needing to care too much about the physical SPIRV module layout.
2155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct spirv_inst_iter {
2165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator zero;
2175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator it;
2185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
219b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t len() {
220b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        auto result = *it >> 16;
221b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(result > 0);
222b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return result;
223b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
224b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t opcode() { return *it & 0x0ffffu; }
226b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
227b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t const &word(unsigned n) {
228b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(n < len());
229b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return it[n];
230b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
231b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset() { return (uint32_t)(it - zero); }
2335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter() {}
2355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {}
2375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator==(spirv_inst_iter const &other) { return it == other.it; }
2395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator!=(spirv_inst_iter const &other) { return it != other.it; }
2415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
242cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++(int) {  // x++
2435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        spirv_inst_iter ii = *this;
2445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return ii;
2465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++() {  // ++x;
2495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return *this;
2515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
25325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The iterator and the value are the same thing.
2545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter &operator*() { return *this; }
2555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter const &operator*() const { return *this; }
2565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module {
25925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The spirv image itself
2605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    vector<uint32_t> words;
26125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // A mapping of <id> to the first word of its def. this is useful because walking type
26225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // trees, constant expressions, etc requires jumping all over the instruction stream.
2635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<unsigned, unsigned> def_index;
264c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    bool has_valid_spirv;
2655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module(VkShaderModuleCreateInfo const *pCreateInfo)
2675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
268c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski          def_index(),
269c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski          has_valid_spirv(true) {
2705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        build_def_index(this);
2715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
273c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    shader_module() : has_valid_spirv(false) {}
274c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski
27525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Expose begin() / end() to enable range-based for
276cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); }  // First insn
277cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); }          // Just past last insn
27825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Given an offset into the module, produce an iterator there.
2795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); }
2805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
28125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Gets an iterator to the definition of an id
2825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter get_def(unsigned id) const {
2835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto it = def_index.find(id);
2845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (it == def_index.end()) {
2855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return end();
2865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return at(it->second);
2885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO : This can be much smarter, using separate locks for separate global data
292b9e992386a44404152747d66817a733aa127e281Jeremy Hayesstatic std::mutex global_lock;
293593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
29479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis// Return IMAGE_VIEW_STATE ptr for specified imageView or else NULL
2959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_VIEW_STATE *GetImageViewState(const layer_data *dev_data, VkImageView image_view) {
2962c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto iv_it = dev_data->imageViewMap.find(image_view);
2972c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (iv_it == dev_data->imageViewMap.end()) {
2982c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis        return nullptr;
2992c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    }
3002c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    return iv_it->second.get();
3012c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis}
3029a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis// Return sampler node ptr for specified sampler or else NULL
3039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSAMPLER_STATE *GetSamplerState(const layer_data *dev_data, VkSampler sampler) {
3042c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto sampler_it = dev_data->samplerMap.find(sampler);
3052c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (sampler_it == dev_data->samplerMap.end()) {
3069a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis        return nullptr;
3079a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    }
3089a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    return sampler_it->second.get();
3099a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis}
3105cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return image state ptr for specified image or else NULL
3119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_STATE *GetImageState(const layer_data *dev_data, VkImage image) {
3126d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    auto img_it = dev_data->imageMap.find(image);
3136d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    if (img_it == dev_data->imageMap.end()) {
3146d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        return nullptr;
3156d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    }
3166d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    return img_it->second.get();
3176d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis}
3185cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return buffer state ptr for specified buffer or else NULL
3199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_STATE *GetBufferState(const layer_data *dev_data, VkBuffer buffer) {
3202c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto buff_it = dev_data->bufferMap.find(buffer);
3212c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (buff_it == dev_data->bufferMap.end()) {
3228718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        return nullptr;
3238718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    }
3248718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    return buff_it->second.get();
3258718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis}
326b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis// Return swapchain node for specified swapchain or else NULL
3279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSWAPCHAIN_NODE *GetSwapchainNode(const layer_data *dev_data, VkSwapchainKHR swapchain) {
32816a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes    auto swp_it = dev_data->swapchainMap.find(swapchain);
32916a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes    if (swp_it == dev_data->swapchainMap.end()) {
330b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        return nullptr;
331b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    }
3323f687bf405355f3eec6bd1bc0e8d04daba37a0f9Tobin Ehlis    return swp_it->second.get();
333b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis}
3342f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis// Return buffer node ptr for specified buffer or else NULL
3359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_VIEW_STATE *GetBufferViewState(const layer_data *dev_data, VkBufferView buffer_view) {
33651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto bv_it = dev_data->bufferViewMap.find(buffer_view);
33751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (bv_it == dev_data->bufferViewMap.end()) {
3382f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis        return nullptr;
3392f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    }
3402f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    return bv_it->second.get();
3412f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis}
3428718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis
3439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFENCE_NODE *GetFenceNode(layer_data *dev_data, VkFence fence) {
34466fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->fenceMap.find(fence);
34566fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->fenceMap.end()) {
34666fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
34766fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
34866fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
34966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
35066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisEVENT_STATE *GetEventNode(layer_data *dev_data, VkEvent event) {
3529556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    auto it = dev_data->eventMap.find(event);
3539556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    if (it == dev_data->eventMap.end()) {
3549556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis        return nullptr;
3559556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    }
3569556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    return &it->second;
3579556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis}
3589556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis
3599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUERY_POOL_NODE *GetQueryPoolNode(layer_data *dev_data, VkQueryPool query_pool) {
360ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    auto it = dev_data->queryPoolMap.find(query_pool);
361ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    if (it == dev_data->queryPoolMap.end()) {
362ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis        return nullptr;
363ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    }
364ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    return &it->second;
365ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis}
366ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis
3679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUEUE_STATE *GetQueueState(layer_data *dev_data, VkQueue queue) {
36866fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->queueMap.find(queue);
36966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->queueMap.end()) {
37066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
37166fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
37266fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
37366fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
37466fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSEMAPHORE_NODE *GetSemaphoreNode(layer_data *dev_data, VkSemaphore semaphore) {
3765e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    auto it = dev_data->semaphoreMap.find(semaphore);
3775e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    if (it == dev_data->semaphoreMap.end()) {
3785e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes        return nullptr;
3795e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    }
3805e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    return &it->second;
3815e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes}
3825e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes
3839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisCOMMAND_POOL_NODE *GetCommandPoolNode(layer_data *dev_data, VkCommandPool pool) {
3848d6a38de0389036581ada119e548180c614fe0efChris Forbes    auto it = dev_data->commandPoolMap.find(pool);
3858d6a38de0389036581ada119e548180c614fe0efChris Forbes    if (it == dev_data->commandPoolMap.end()) {
3868d6a38de0389036581ada119e548180c614fe0efChris Forbes        return nullptr;
3878d6a38de0389036581ada119e548180c614fe0efChris Forbes    }
3888d6a38de0389036581ada119e548180c614fe0efChris Forbes    return &it->second;
3898d6a38de0389036581ada119e548180c614fe0efChris Forbes}
3903bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
3919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisPHYSICAL_DEVICE_STATE *GetPhysicalDeviceState(instance_layer_data *instance_data, VkPhysicalDevice phys) {
392f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    auto it = instance_data->physical_device_map.find(phys);
393f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    if (it == instance_data->physical_device_map.end()) {
3943bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes        return nullptr;
3953bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    }
3963bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    return &it->second;
3973bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes}
3983bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
3999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSURFACE_STATE *GetSurfaceState(instance_layer_data *instance_data, VkSurfaceKHR surface) {
400747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    auto it = instance_data->surface_map.find(surface);
401747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (it == instance_data->surface_map.end()) {
402747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        return nullptr;
403747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
404747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return &it->second;
405747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
406747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
407f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Return ptr to memory binding for given handle of specified type
4087a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic BINDABLE *GetObjectMemBinding(layer_data *dev_data, uint64_t handle, VulkanObjectType type) {
4095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type) {
4107a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        case kVulkanObjectTypeImage:
4119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetImageState(dev_data, VkImage(handle));
4127a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        case kVulkanObjectTypeBuffer:
4139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetBufferState(dev_data, VkBuffer(handle));
414cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
415cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
4165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41794c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis    return nullptr;
4185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
41972d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis// prototype
4209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *, const VkCommandBuffer);
42172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis
4225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return ptr to info in map container containing mem, or NULL if not found
4235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Calls to this function should be wrapped in mutex
4249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDEVICE_MEM_INFO *GetMemObjInfo(const layer_data *dev_data, const VkDeviceMemory mem) {
42557fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    auto mem_it = dev_data->memObjMap.find(mem);
42657fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_it == dev_data->memObjMap.end()) {
4275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
4285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
42957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    return mem_it->second.get();
4305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void add_mem_obj_info(layer_data *dev_data, void *object, const VkDeviceMemory mem,
4335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             const VkMemoryAllocateInfo *pAllocateInfo) {
4345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(object != NULL);
4355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->memObjMap[mem] = unique_ptr<DEVICE_MEM_INFO>(new DEVICE_MEM_INFO(object, mem, pAllocateInfo));
4375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
438dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis
439cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given bound_object_handle, bound to given mem allocation, verify that the range for the bound object is valid
4407a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ValidateMemoryIsValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t bound_object_handle, VulkanObjectType type,
4417a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                  const char *functionName) {
4429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
443f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
444f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        if (!mem_info->bound_ranges[bound_object_handle].valid) {
445f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4469b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
447dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           "%s: Cannot read invalid region of memory allocation 0x%" PRIx64 " for bound %s object 0x%" PRIx64
448dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           ", please fill the memory before using.",
4499b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           functionName, HandleToUint64(mem), object_string[type], bound_object_handle);
450f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        }
451f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
452f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    return false;
453f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
4541facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis// For given image_state
4551facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then verify that image_state valid member is true
456f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else verify that the image's bound memory range is valid
45760568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageMemoryIsValid(layer_data *dev_data, IMAGE_STATE *image_state, const char *functionName) {
458e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
4591facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        if (!image_state->valid) {
460f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4619b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(image_state->binding.mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
462414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                           "%s: Cannot read invalid swapchain image 0x%" PRIx64 ", please fill the memory before using.",
4639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           functionName, HandleToUint64(image_state->image));
4645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
4669b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        return ValidateMemoryIsValid(dev_data, image_state->binding.mem, HandleToUint64(image_state->image), kVulkanObjectTypeImage,
4679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                     functionName);
4685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
4705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4715cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// For given buffer_state, verify that the range it's bound to is valid
472c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskibool ValidateBufferMemoryIsValid(layer_data *dev_data, BUFFER_STATE *buffer_state, const char *functionName) {
4739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    return ValidateMemoryIsValid(dev_data, buffer_state->binding.mem, HandleToUint64(buffer_state->buffer), kVulkanObjectTypeBuffer,
4749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                 functionName);
475f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
476f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For the given memory allocation, set the range bound by the given handle object to the valid param value
477f989de4217bce0f293121d0da53dc8328276370fTobin Ehlisstatic void SetMemoryValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, bool valid) {
4789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
479f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
480f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        mem_info->bound_ranges[handle].valid = valid;
481f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
482f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
483f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given image node
4841facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then set entire image_state to valid param value
485f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else set the image's bound memory range to valid param value
486623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinskivoid SetImageMemoryValid(layer_data *dev_data, IMAGE_STATE *image_state, bool valid) {
487e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
4881facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->valid = valid;
4895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
4909b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        SetMemoryValid(dev_data, image_state->binding.mem, HandleToUint64(image_state->image), valid);
4915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
493f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given buffer node set the buffer's bound memory range to valid param value
494c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskivoid SetBufferMemoryValid(layer_data *dev_data, BUFFER_STATE *buffer_state, bool valid) {
4959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    SetMemoryValid(dev_data, buffer_state->binding.mem, HandleToUint64(buffer_state->buffer), valid);
496f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
497ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
49856f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given sampler and command buffer node
499d31a44af6da568692a73201825459689c9431867Tobin Ehlisvoid AddCommandBufferBindingSampler(GLOBAL_CB_NODE *cb_node, SAMPLER_STATE *sampler_state) {
500d31a44af6da568692a73201825459689c9431867Tobin Ehlis    sampler_state->cb_bindings.insert(cb_node);
5019b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(sampler_state->sampler), kVulkanObjectTypeSampler});
50256f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis}
50356f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis
50456f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given image node and command buffer node
5051facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisvoid AddCommandBufferBindingImage(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state) {
506ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Skip validation if this image was created through WSI
507e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
508ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // First update CB binding in MemObj mini CB list
509d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        for (auto mem_binding : image_state->GetBoundMemory()) {
5109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
511d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            if (pMemInfo) {
512d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                pMemInfo->cb_bindings.insert(cb_node);
513d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                // Now update CBInfo's Mem reference list
514d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                cb_node->memObjs.insert(mem_binding);
515d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            }
516ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        }
517f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        // Now update cb binding for image
5189b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        cb_node->object_bindings.insert({HandleToUint64(image_state->image), kVulkanObjectTypeImage});
5191facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->cb_bindings.insert(cb_node);
520ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
521ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
522ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
52303ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis// Create binding link between given image view node and its image with command buffer node
52403ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlisvoid AddCommandBufferBindingImageView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state) {
52503ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // First add bindings for imageView
52603ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
5279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(view_state->image_view), kVulkanObjectTypeImageView});
5289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, view_state->create_info.image);
52903ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // Add bindings for image within imageView
5301facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
5311facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
53203ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    }
53303ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis}
53403ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis
535ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis// Create binding link between given buffer node and command buffer node
5365cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlisvoid AddCommandBufferBindingBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state) {
537ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // First update CB binding in MemObj mini CB list
5385cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    for (auto mem_binding : buffer_state->GetBoundMemory()) {
5399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
540d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        if (pMemInfo) {
541d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            pMemInfo->cb_bindings.insert(cb_node);
542d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            // Now update CBInfo's Mem reference list
543d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            cb_node->memObjs.insert(mem_binding);
544d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        }
545ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
546ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Now update cb binding for buffer
5479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(buffer_state->buffer), kVulkanObjectTypeBuffer});
5485cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    buffer_state->cb_bindings.insert(cb_node);
549ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
550ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
55177b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis// Create binding link between given buffer view node and its buffer with command buffer node
55277b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlisvoid AddCommandBufferBindingBufferView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_VIEW_STATE *view_state) {
55377b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // First add bindings for bufferView
55477b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
5559b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(view_state->buffer_view), kVulkanObjectTypeBufferView});
5569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, view_state->create_info.buffer);
55777b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // Add bindings for buffer within bufferView
5585cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
5595cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, buffer_state);
56077b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    }
56177b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis}
56277b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis
563400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis// For every mem obj bound to particular CB, free bindings related to that CB
564d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlisstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
565d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis    if (cb_node) {
566d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        if (cb_node->memObjs.size() > 0) {
567d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            for (auto mem : cb_node->memObjs) {
5689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                DEVICE_MEM_INFO *pInfo = GetMemObjInfo(dev_data, mem);
5695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pInfo) {
570d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                    pInfo->cb_bindings.erase(cb_node);
5715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
5725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
573d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            cb_node->memObjs.clear();
5745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
575d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        cb_node->validate_functions.clear();
5765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
579f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Clear a single object binding from given memory object, or report error if binding is missing
5807a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ClearMemoryObjectBinding(layer_data *dev_data, uint64_t handle, VulkanObjectType type, VkDeviceMemory mem) {
5819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
582f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // This obj is bound to a memory object. Remove the reference to this object in that memory object's list
583d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes    if (mem_info) {
584d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes        mem_info->obj_bindings.erase({handle, type});
585f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    }
586f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return false;
587f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis}
588f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis
589f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// ClearMemoryObjectBindings clears the binding of objects to memory
590f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  For the given object it pulls the memory bindings and makes sure that the bindings
591f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  no longer refer to the object being cleared. This occurs when objects are destroyed.
5927a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskibool ClearMemoryObjectBindings(layer_data *dev_data, uint64_t handle, VulkanObjectType type) {
593f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    bool skip = false;
594f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
595f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (mem_binding) {
596f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (!mem_binding->sparse) {
597f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            skip = ClearMemoryObjectBinding(dev_data, handle, type, mem_binding->binding.mem);
598cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Sparse, clear all bindings
599bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            for (auto &sparse_mem_binding : mem_binding->sparse_bindings) {
600f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                skip |= ClearMemoryObjectBinding(dev_data, handle, type, sparse_mem_binding.mem);
6015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
6025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
604f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return skip;
6055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
607888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// For given mem object, verify that it is not null or UNBOUND, if it is, report error. Return skip value.
608888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisbool VerifyBoundMemoryIsValid(const layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, const char *api_name,
60935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                              const char *type_name, UNIQUE_VALIDATION_ERROR_CODE error_code) {
610888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    bool result = false;
611888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    if (VK_NULL_HANDLE == mem) {
612888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
613cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
614cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound. Memory should be bound by calling "
615cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "vkBind%sMemory(). %s",
61635ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, type_name, validation_error_map[error_code]);
617888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    } else if (MEMORY_UNBOUND == mem) {
618888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
619cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
620cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound and previously bound memory was freed. "
621cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "Memory must not be freed prior to this operation. %s",
62235ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, validation_error_map[error_code]);
623888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    }
624888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    return result;
625888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis}
626888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis
627b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was ever bound to this image
62835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToImage(const layer_data *dev_data, const IMAGE_STATE *image_state, const char *api_name,
62935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                  UNIQUE_VALIDATION_ERROR_CODE error_code) {
630b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
6311facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (0 == (static_cast<uint32_t>(image_state->createInfo.flags) & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
6329b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        result = VerifyBoundMemoryIsValid(dev_data, image_state->binding.mem, HandleToUint64(image_state->image), api_name, "Image",
6339b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                          error_code);
634b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
635b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
636b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
637b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
638b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was bound to this buffer
63935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToBuffer(const layer_data *dev_data, const BUFFER_STATE *buffer_state, const char *api_name,
64035ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                   UNIQUE_VALIDATION_ERROR_CODE error_code) {
641b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
6425cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (0 == (static_cast<uint32_t>(buffer_state->createInfo.flags) & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) {
6439b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        result = VerifyBoundMemoryIsValid(dev_data, buffer_state->binding.mem, HandleToUint64(buffer_state->buffer), api_name,
6449b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                          "Buffer", error_code);
645b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
646b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
647b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
648b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
6493a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// SetMemBinding is used to establish immutable, non-sparse binding between a single image/buffer object and memory object.
6503a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Corresponding valid usage checks are in ValidateSetMemBinding().
6517a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic void SetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VulkanObjectType type, const char *apiName) {
652c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    if (mem != VK_NULL_HANDLE) {
653c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
654c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        assert(mem_binding);
655c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
656c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        if (mem_info) {
657c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_info->obj_bindings.insert({handle, type});
658c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // For image objects, make sure default memory state is correctly set
659c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // TODO : What's the best/correct way to handle this?
6607a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            if (kVulkanObjectTypeImage == type) {
661c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                auto const image_state = GetImageState(dev_data, VkImage(handle));
662c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                if (image_state) {
663c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    VkImageCreateInfo ici = image_state->createInfo;
664c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
665c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                        // TODO::  More memory state transition stuff.
666c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    }
667c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                }
668c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            }
669c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_binding->binding.mem = mem;
670c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        }
671c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    }
672c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton}
6733a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton
6743a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Valid usage checks for a call to SetMemBinding().
6753a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// For NULL mem case, output warning
6763a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Make sure given object is in global object map
6773a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  IF a previous binding existed, output validation error
6783a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Otherwise, add reference from objectInfo to memoryInfo
6793a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Add reference off of objInfo
6803a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// TODO: We may need to refactor or pass in multiple valid usage statements to handle multiple valid usage conditions.
6817a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ValidateSetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VulkanObjectType type,
682c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                                  const char *apiName) {
6833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
684f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // It's an error to bind an object to NULL memory
685d3876b4ff7c293a14f73fe3622513d1fa91bf2d0Jeremy Hayes    if (mem != VK_NULL_HANDLE) {
686f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
687888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        assert(mem_binding);
68810ffe2d353eaff714ed92a2835af77d8b5042d31Cort        if (mem_binding->sparse) {
689315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_1740082a;
69010ffe2d353eaff714ed92a2835af77d8b5042d31Cort            const char *handle_type = "IMAGE";
69174300755ed9ec780d6073af71e47f201217008d6Cort Stratton            if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
692315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                error_code = VALIDATION_ERROR_1700080c;
69310ffe2d353eaff714ed92a2835af77d8b5042d31Cort                handle_type = "BUFFER";
69410ffe2d353eaff714ed92a2835af77d8b5042d31Cort            } else {
69574300755ed9ec780d6073af71e47f201217008d6Cort Stratton                assert(strcmp(apiName, "vkBindImageMemory()") == 0);
69610ffe2d353eaff714ed92a2835af77d8b5042d31Cort            }
6973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
6989b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem), __LINE__, error_code, "MEM",
6993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
7003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") which was created with sparse memory flags (VK_%s_CREATE_SPARSE_*_BIT). %s",
7019b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            apiName, HandleToUint64(mem), handle, handle_type, validation_error_map[error_code]);
70210ffe2d353eaff714ed92a2835af77d8b5042d31Cort        }
7039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
704888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        if (mem_info) {
7059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *prev_binding = GetMemObjInfo(dev_data, mem_binding->binding.mem);
706888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis            if (prev_binding) {
707315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_17400828;
70874300755ed9ec780d6073af71e47f201217008d6Cort Stratton                if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
709315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    error_code = VALIDATION_ERROR_1700080a;
71098c2a17e1a549df84f4239f619bc0955f632cb43Cort                } else {
71174300755ed9ec780d6073af71e47f201217008d6Cort Stratton                    assert(strcmp(apiName, "vkBindImageMemory()") == 0);
71298c2a17e1a549df84f4239f619bc0955f632cb43Cort                }
7133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
7149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(mem), __LINE__, error_code, "MEM",
7153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
7163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                ") which has already been bound to mem object 0x%" PRIxLEAST64 ". %s",
7179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                apiName, HandleToUint64(mem), handle, HandleToUint64(prev_binding->mem),
7183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                validation_error_map[error_code]);
719f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            } else if (mem_binding->binding.mem == MEMORY_UNBOUND) {
7203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
7219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(mem), __LINE__, MEMTRACK_REBIND_OBJECT, "MEM",
7223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
7233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                ") which was previous bound to memory that has since been freed. Memory bindings are immutable in "
7243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "Vulkan so this attempt to bind to new memory is not allowed.",
7259b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                apiName, HandleToUint64(mem), handle);
7265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
7305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
7315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For NULL mem case, clear any previous binding Else...
7335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Make sure given object is in its object map
7345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  IF a previous binding existed, update binding
7355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference from objectInfo to memoryInfo
7365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference off of object's binding info
7370a1ce3dfd81c9f4efbe46f5ba5ddaea70bc4aa61Chris Forbes// Return VK_TRUE if addition is successful, VK_FALSE otherwise
738ece0e981ee4a5ad2572d146a89fc64d699d79f36Chris Forbesstatic bool SetSparseMemBinding(layer_data *dev_data, MEM_BINDING binding, uint64_t handle, VulkanObjectType type) {
7393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = VK_FALSE;
7405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Handle NULL case separately, just clear previous binding & decrement reference
741f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (binding.mem == VK_NULL_HANDLE) {
742f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        // TODO : This should cause the range of the resource to be unbound according to spec
7435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
744f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
745f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding);
746f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding->sparse);
7479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, binding.mem);
748f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (mem_info) {
749f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_info->obj_bindings.insert({handle, type});
7502e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis            // Need to set mem binding for this object
751f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_binding->sparse_bindings.insert(binding);
7525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
755caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis}
756caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis
7575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// SPIRV utility functions
7585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *module) {
7595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *module) {
7605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
761cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Types
762cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVoid:
763cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeBool:
764cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeInt:
765cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFloat:
766cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVector:
767cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeMatrix:
768cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage:
769cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampler:
770cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
771cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
772cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeRuntimeArray:
773cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeStruct:
774cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeOpaque:
775cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
776cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFunction:
777cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeEvent:
778cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeDeviceEvent:
779cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeReserveId:
780cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeQueue:
781cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePipe:
782cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(1)] = insn.offset();
783cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
7845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
785cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Fixed constants
786cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantTrue:
787cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantFalse:
788cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstant:
789cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantComposite:
790cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantSampler:
791cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantNull:
792cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
793cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
7945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
795cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Specialization constants
796cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantTrue:
797cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantFalse:
798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstant:
799cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantComposite:
800cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantOp:
801cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
802cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
804cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Variables
805cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpVariable:
806cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
807cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
809cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Functions
810cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
811cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
812cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
814cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
815cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // We don't care about any other defs for now.
816cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) {
8225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
8235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpEntryPoint) {
8245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointName = (char const *)&insn.word(3);
8255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointStageBits = 1u << insn.word(1);
8265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) {
8285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return insn;
8295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return src->end();
8345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char const *storage_class_name(unsigned sc) {
8375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (sc) {
838cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassInput:
839cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "input";
840cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassOutput:
841cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "output";
842cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniformConstant:
843cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "const uniform";
844cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniform:
845cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "uniform";
846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassWorkgroup:
847cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup local";
848cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassCrossWorkgroup:
849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup global";
850cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPrivate:
851cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "private global";
852cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassFunction:
853cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "function";
854cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassGeneric:
855cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "generic";
856cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassAtomicCounter:
857cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "atomic counter";
858cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassImage:
859cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image";
860cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPushConstant:
861cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "push constant";
862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
863cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "unknown";
8645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
86725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Get the value of an integral constant
8685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisunsigned get_constant_value(shader_module const *src, unsigned id) {
8695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto value = src->get_def(id);
8705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(value != src->end());
8715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (value.opcode() != spv::OpConstant) {
87325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // TODO: Either ensure that the specialization transform is already performed on a module we're
87425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        //       considering here, OR -- specialize on the fly now.
8755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return 1;
8765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return value.word(3);
8795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8819ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) {
8825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
8835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
8845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
887cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "bool";
888cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
889cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
890cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
892cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "float" << insn.word(2);
894cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "vec" << insn.word(3) << " of ";
897cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "mat" << insn.word(3) << " of ";
901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of ";
905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "ptr to " << storage_class_name(insn.word(2)) << " ";
909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(3));
910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "struct of (";
913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (unsigned i = 2; i < insn.len(); i++) {
914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                describe_type_inner(ss, src, insn.word(i));
915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (i == insn.len() - 1) {
916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ")";
917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ", ";
919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
9209ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes            }
921cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
923cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler";
925cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
926cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
927cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler+";
928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "oddtype";
935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9399ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic std::string describe_type(shader_module const *src, unsigned type) {
9409ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    std::ostringstream ss;
9419ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    describe_type_inner(ss, src, type);
9429ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    return ss.str();
9439ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes}
9449ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes
945bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool is_narrow_numeric_type(spirv_inst_iter type) {
946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat) return false;
94737576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    return type.word(2) < 64;
94837576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes}
94937576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
950bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool a_arrayed,
951bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        bool b_arrayed, bool relaxed) {
95225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk two type trees together, and complain about differences
9535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_insn = a->get_def(a_type);
9545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_insn = b->get_def(b_type);
9555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(a_insn != a->end());
9565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(b_insn != b->end());
9575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9587c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
95937576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
9607c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
9617c755c8aca6857046df9516d8336416165969cb9Chris Forbes
9625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
96325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We probably just found the extra level of arrayness in b_type: compare the type inside it to a_type
96437576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
96537576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    }
96637576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
96737576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    if (a_insn.opcode() == spv::OpTypeVector && relaxed && is_narrow_numeric_type(b_insn)) {
96837576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
9695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (a_insn.opcode() != b_insn.opcode()) {
9725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
9735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9757c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_insn.opcode() == spv::OpTypePointer) {
97625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Match on pointee type. storage class is expected to differ
97737576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
9787c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
9797c755c8aca6857046df9516d8336416165969cb9Chris Forbes
9807c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed || b_arrayed) {
98125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // If we havent resolved array-of-verts by here, we're not going to.
9827c755c8aca6857046df9516d8336416165969cb9Chris Forbes        return false;
9837c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
9847c755c8aca6857046df9516d8336416165969cb9Chris Forbes
9855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (a_insn.opcode()) {
986cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
987cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return true;
988cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
989cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width, signedness
990cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
991cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
992cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width
993cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2);
994cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
995cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
996cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (!types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false)) return false;
997cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (relaxed && is_narrow_numeric_type(a->get_def(a_insn.word(2)))) {
998cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) >= b_insn.word(3);
999cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1000cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) == b_insn.word(3);
10015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1002cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1003cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1004cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1005cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   a_insn.word(3) == b_insn.word(3);
1006cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1007cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count. these all have the same layout. we don't get here if b_arrayed. This differs from
1008cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // vector & matrix types in that the array size is the id of a constant instruction, * not a literal within OpTypeArray
1009cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1010cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3));
1011cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct:
1012cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on all element types
1013cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            {
1014cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (a_insn.len() != b_insn.len()) {
1015cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return false;  // Structs cannot match if member counts differ
1016cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
10175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1018cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                for (unsigned i = 2; i < a_insn.len(); i++) {
1019cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (!types_match(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
1020cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return false;
1021cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
1022cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
1023cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1024cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return true;
1025cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1026cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1027cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Remaining types are CLisms, or may not appear in the interfaces we are interested in. Just claim no match.
1028cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
10295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10322c81be6aa02b10d9e225329977fa108ceda890a2Chris Forbesstatic unsigned value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, unsigned def) {
10335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it = map.find(id);
10345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (it == map.end())
10355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return def;
10365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    else
10375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return it->second;
10385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) {
10415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
10425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
10435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1045cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1046cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
1047cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // pointers around.
1048cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_locations_consumed_by_type(src, insn.word(3), strip_array_level);
1049cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1050cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (strip_array_level) {
1051cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_locations_consumed_by_type(src, insn.word(2), false);
1052cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1053cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false);
1054cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1055cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1056cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Num locations is the dimension * element size
1057cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false);
1058cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector: {
1059cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto scalar_type = src->get_def(insn.word(2));
1060cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto bit_width =
1061cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
1062cc52143fc093e1e62d2dacc4abc3966e04b6f6d6Chris Forbes
1063cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Locations are 128-bit wide; 3- and 4-component vectors of 64 bit types require two.
1064cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return (bit_width * insn.word(3) + 127) / 128;
1065cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1066cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1067cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Everything else is just 1.
1068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
10695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO: extend to handle 64bit scalar types, whose vectors may need multiple locations.
10715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1074c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbesstatic unsigned get_locations_consumed_by_format(VkFormat format) {
1075c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    switch (format) {
1076cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SFLOAT:
1077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SINT:
1078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_UINT:
1079cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SFLOAT:
1080cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SINT:
1081cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_UINT:
1082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 2;
1083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1084cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
1085c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    }
1086c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes}
1087c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes
10885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> location_t;
10895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> descriptor_slot_t;
10905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct interface_var {
10925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t id;
10935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t type_id;
10945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset;
1095b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    bool is_patch;
1096fff9393206f66a154438e16fa0562c989f425498Chris Forbes    bool is_block_member;
1097b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    bool is_relaxed_precision;
109825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: collect the name, too? Isn't required to be present.
10995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
11005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1101031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstruct shader_stage_attributes {
1102031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    char const *const name;
1103031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_input;
1104031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_output;
1105031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1106031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
1107031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstatic shader_stage_attributes shader_stage_attribs[] = {
1108bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"vertex shader", false, false},  {"tessellation control shader", true, true}, {"tessellation evaluation shader", true, false},
1109bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"geometry shader", true, false}, {"fragment shader", false, false},
1110031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1111031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
11125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) {
11135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (true) {
11145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def.opcode() == spv::OpTypePointer) {
11155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(3));
11165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
11175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(2));
11185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            is_array_of_verts = false;
11195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeStruct) {
11205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return def;
11215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
11225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return src->end();
11235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
11265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1127bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void collect_interface_block_members(shader_module const *src, std::map<location_t, interface_var> *out,
11285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                            std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts,
1129b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                                            uint32_t id, uint32_t type_id, bool is_patch) {
113025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk down the type_id presented, trying to determine whether it's actually an interface block.
1131031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts && !is_patch);
11325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) {
113325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // This isn't an interface block.
11345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return;
11355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> member_components;
11385b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes    std::unordered_map<unsigned, unsigned> member_relaxed_precision;
11395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
114025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk all the OpMemberDecorate for type's result id -- first pass, collect components.
11415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
11425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
11435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
11445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationComponent) {
11465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = insn.word(4);
11475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                member_components[member_index] = component;
11485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
11495b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes
11505b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            if (insn.word(3) == spv::DecorationRelaxedPrecision) {
11515b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                member_relaxed_precision[member_index] = 1;
11525b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            }
11535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
115625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Second pass -- produce the output, from Location decorations
11575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
11585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
11595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
11605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_type_id = type.word(2 + member_index);
11615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationLocation) {
11635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned location = insn.word(4);
11645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false);
11655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto component_it = member_components.find(member_index);
11665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = component_it == member_components.end() ? 0 : component_it->second;
11675b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                bool is_relaxed_precision = member_relaxed_precision.find(member_index) != member_relaxed_precision.end();
11685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1170b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
11715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
117225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                    // TODO: member index in interface_var too?
11735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = member_type_id;
11745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1175b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1176fff9393206f66a154438e16fa0562c989f425498Chris Forbes                    v.is_block_member = true;
11775b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
11783a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                    (*out)[std::make_pair(location + offset, component)] = v;
11795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
11805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
11815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
11845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1185bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic std::map<location_t, interface_var> collect_interface_by_location(shader_module const *src, spirv_inst_iter entrypoint,
1186bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                         spv::StorageClass sinterface, bool is_array_of_verts) {
11875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_locations;
11885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_builtins;
11895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_components;
11905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> blocks;
1191b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    std::unordered_map<unsigned, unsigned> var_patch;
1192b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    std::unordered_map<unsigned, unsigned> var_relaxed_precision;
11935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
119525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We consider two interface models: SSO rendezvous-by-location, and builtins. Complain about anything that
119625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // fits neither model.
11975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
11985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationLocation) {
11995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_locations[insn.word(1)] = insn.word(3);
12005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBuiltIn) {
12035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_builtins[insn.word(1)] = insn.word(3);
12045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationComponent) {
12075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_components[insn.word(1)] = insn.word(3);
12085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBlock) {
12115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                blocks[insn.word(1)] = 1;
12125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1213b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes
1214b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            if (insn.word(2) == spv::DecorationPatch) {
1215b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                var_patch[insn.word(1)] = 1;
1216b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            }
1217b0436668e6594b8528e96de7bed208399fb2431dChris Forbes
1218b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            if (insn.word(2) == spv::DecorationRelaxedPrecision) {
1219b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                var_relaxed_precision[insn.word(1)] = 1;
1220b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            }
12215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
122425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle grouped decorations
122525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle index=1 dual source outputs from FS -- two vars will have the same location, and we DON'T want to clobber.
12265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
122725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the end of the entrypoint's name string. additional zero bytes follow the actual null terminator, to fill out the
122825002b75574f762c62b1a00a595bab04ebb25452Mark 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.
1229c15b801a6e1a5dd5eed09e689aecdde7c4a90a5bMichael Mc Donnell    uint32_t word = 3;
12305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (entrypoint.word(word) & 0xff000000u) {
12315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ++word;
12325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ++word;
12345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12353a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::map<location_t, interface_var> out;
12363a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
12375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; word < entrypoint.len(); word++) {
12385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(entrypoint.word(word));
12395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
12405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn.opcode() == spv::OpVariable);
12415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12421d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill        if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
12435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned id = insn.word(2);
12445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned type = insn.word(1);
12455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int location = value_or_default(var_locations, id, -1);
12475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int builtin = value_or_default(var_builtins, id, -1);
1248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            unsigned component = value_or_default(var_components, id, 0);  // Unspecified is OK, is 0
1249b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            bool is_patch = var_patch.find(id) != var_patch.end();
1250b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            bool is_relaxed_precision = var_relaxed_precision.find(id) != var_relaxed_precision.end();
12515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
125225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // All variables and interface block members in the Input or Output storage classes must be decorated with either
125325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // a builtin or an explicit location.
125425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            //
125525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // TODO: integrate the interface block support here. For now, don't complain -- a valid SPIRV module will only hit
125625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // this path for the interface block case, as the individual members of the type are decorated, rather than
125725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // variable declarations.
12585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (location != -1) {
126025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // A user-defined interface variable, with a location. Where a variable occupied multiple locations, emit
126125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // one result for each.
12627c755c8aca6857046df9516d8336416165969cb9Chris Forbes                unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts && !is_patch);
12635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1264b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
12655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
12665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = type;
12675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1268b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1269b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
12705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    out[std::make_pair(location + offset, component)] = v;
12715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
12725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (builtin == -1) {
127325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // An interface block instance
12743a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                collect_interface_block_members(src, &out, blocks, is_array_of_verts, id, type, is_patch);
12755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12783a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
12793a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
12805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
128212b7fc342b53fbdd399aae4a85959e37685936acChris Forbesstatic vector<std::pair<uint32_t, interface_var>> collect_interface_by_input_attachment_index(
128312b7fc342b53fbdd399aae4a85959e37685936acChris Forbes    shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
12843a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<uint32_t, interface_var>> out;
1285745d49409296f060402b57950384caadb636a2b2Chris Forbes
1286745d49409296f060402b57950384caadb636a2b2Chris Forbes    for (auto insn : *src) {
1287745d49409296f060402b57950384caadb636a2b2Chris Forbes        if (insn.opcode() == spv::OpDecorate) {
1288745d49409296f060402b57950384caadb636a2b2Chris Forbes            if (insn.word(2) == spv::DecorationInputAttachmentIndex) {
1289745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto attachment_index = insn.word(3);
1290745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto id = insn.word(1);
1291745d49409296f060402b57950384caadb636a2b2Chris Forbes
1292745d49409296f060402b57950384caadb636a2b2Chris Forbes                if (accessible_ids.count(id)) {
1293745d49409296f060402b57950384caadb636a2b2Chris Forbes                    auto def = src->get_def(id);
1294745d49409296f060402b57950384caadb636a2b2Chris Forbes                    assert(def != src->end());
1295745d49409296f060402b57950384caadb636a2b2Chris Forbes
1296745d49409296f060402b57950384caadb636a2b2Chris Forbes                    if (def.opcode() == spv::OpVariable && insn.word(3) == spv::StorageClassUniformConstant) {
1297e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        auto num_locations = get_locations_consumed_by_type(src, def.word(1), false);
1298e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        for (unsigned int offset = 0; offset < num_locations; offset++) {
1299b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                            interface_var v = {};
1300e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.id = id;
1301e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.type_id = def.word(1);
1302e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.offset = offset;
1303e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            out.emplace_back(attachment_index + offset, v);
1304e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        }
1305745d49409296f060402b57950384caadb636a2b2Chris Forbes                    }
1306745d49409296f060402b57950384caadb636a2b2Chris Forbes                }
1307745d49409296f060402b57950384caadb636a2b2Chris Forbes            }
1308745d49409296f060402b57950384caadb636a2b2Chris Forbes        }
1309745d49409296f060402b57950384caadb636a2b2Chris Forbes    }
13103a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
13113a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
1312745d49409296f060402b57950384caadb636a2b2Chris Forbes}
1313745d49409296f060402b57950384caadb636a2b2Chris Forbes
1314cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic std::vector<std::pair<descriptor_slot_t, interface_var>> collect_interface_by_descriptor_slot(
1315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
13165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_sets;
13175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_bindings;
13185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
132025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // All variables in the Uniform or UniformConstant storage classes are required to be decorated with both
132125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // DecorationDescriptorSet and DecorationBinding.
13225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
13235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationDescriptorSet) {
13245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_sets[insn.word(1)] = insn.word(3);
13255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBinding) {
13285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_bindings[insn.word(1)] = insn.word(3);
13295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13333a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<descriptor_slot_t, interface_var>> out;
13343a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
13355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
13365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
13375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
13385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpVariable &&
13405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) {
13415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned set = value_or_default(var_sets, insn.word(2), 0);
13425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned binding = value_or_default(var_bindings, insn.word(2), 0);
13435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1344b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            interface_var v = {};
13455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.id = insn.word(2);
13465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.type_id = insn.word(1);
1347cefd4dd8e03c5dae11a05d04a03cb856190358e0Chris Forbes            out.emplace_back(std::make_pair(set, binding), v);
13485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13503a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
13513a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
13525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
13535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1354edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_interface_between_stages(debug_report_data *report_data, shader_module const *producer,
1355031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              spirv_inst_iter producer_entrypoint, shader_stage_attributes const *producer_stage,
13565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                              shader_module const *consumer, spirv_inst_iter consumer_entrypoint,
1357031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              shader_stage_attributes const *consumer_stage) {
13581b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
13595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1360bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto outputs =
1361bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(producer, producer_entrypoint, spv::StorageClassOutput, producer_stage->arrayed_output);
1362bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto inputs =
1363bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(consumer, consumer_entrypoint, spv::StorageClassInput, consumer_stage->arrayed_input);
13645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_it = outputs.begin();
13665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_it = inputs.begin();
13675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
136825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Maps sorted by key (location); walk them together to find mismatches
13695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
13705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
13715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
13725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
13735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
13745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
13761b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
13771b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
13781b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "%s writes to output location %u.%u which is not consumed by %s", producer_stage->name, a_first.first,
13791b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            a_first.second, consumer_stage->name);
13805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
13815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (a_at_end || a_first > b_first) {
13821b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
13831b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "%s consumes input location %u.%u which is not written by %s",
13841b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            consumer_stage->name, b_first.first, b_first.second, producer_stage->name);
13855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
13865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1387fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // subtleties of arrayed interfaces:
1388fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_patch, then the member is not arrayed, even though the interface may be.
1389fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_block_member, then the extra array level of an arrayed interface is not
1390fff9393206f66a154438e16fa0562c989f425498Chris Forbes            //   expressed in the member type -- it's expressed in the block type.
13910f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (!types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id,
1392fff9393206f66a154438e16fa0562c989f425498Chris Forbes                             producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
1393bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member, true)) {
13941b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
13951b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'",
13961b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                a_first.first, a_first.second, describe_type(producer, a_it->second.type_id).c_str(),
13971b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                describe_type(consumer, b_it->second.type_id).c_str());
13985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13990f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (a_it->second.is_patch != b_it->second.is_patch) {
14001b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
14011b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
14021b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Decoration mismatch on location %u.%u: is per-%s in %s stage but "
14031b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "per-%s in %s stage",
14041b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                a_first.first, a_first.second, a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
14051b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name);
14060f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            }
140717c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            if (a_it->second.is_relaxed_precision != b_it->second.is_relaxed_precision) {
14081b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
14091b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
14101b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Decoration mismatch on location %u.%u: %s and %s stages differ in precision", a_first.first,
14111b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                a_first.second, producer_stage->name, consumer_stage->name);
141217c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            }
14135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
14145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
14155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14181b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
14195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisenum FORMAT_TYPE {
1422f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_FLOAT = 1,  // UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader
1423f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_SINT = 2,
1424f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_UINT = 4,
14255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
14265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_format_type(VkFormat fmt) {
142828f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (FormatIsSInt(fmt))
142928f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return FORMAT_TYPE_SINT;
143028f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (FormatIsUInt(fmt))
143128f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return FORMAT_TYPE_UINT;
143228f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (FormatIsDepthAndStencil(fmt))
143328f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return FORMAT_TYPE_FLOAT | FORMAT_TYPE_UINT;
143428f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (fmt == VK_FORMAT_UNDEFINED)
143528f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return 0;
143628f7140700a1624f4836243204237c80645e0fb9Chris Forbes    // everything else -- UNORM/SNORM/FLOAT/USCALED/SSCALED is all float in the shader.
143728f7140700a1624f4836243204237c80645e0fb9Chris Forbes    return FORMAT_TYPE_FLOAT;
14385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
144025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// characterizes a SPIR-V type appearing in an interface to a FF stage, for comparison to a VkFormat's characterization above.
14415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_fundamental_type(shader_module const *src, unsigned type) {
14425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
14435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
14445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1446cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1447cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
1448cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1449cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_FLOAT;
1450cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(3));
1458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
1459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1460cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1462f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            return 0;
14635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) {
14678e88ad80aacad2085e76016e7bb29d243ce7f7b6Chris Forbes    uint32_t bit_pos = uint32_t(u_ffs(stage));
14685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return bit_pos - 1;
14695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1471edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_consistency(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi) {
147225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk the binding descriptions, which describe the step rate and stride of each vertex buffer.  Each binding should
147325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // be specified only once.
14745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
14751b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
14765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
14785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto desc = &vi->pVertexBindingDescriptions[i];
14795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto &binding = bindings[desc->binding];
14805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (binding) {
1481315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // TODO: VALIDATION_ERROR_096005cc perhaps?
14821b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1483bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INCONSISTENT_VI, "SC", "Duplicate vertex input binding descriptions for binding %d",
14841b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                        desc->binding);
14855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
14865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            binding = desc;
14875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14901b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
14915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1493edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_against_vs_inputs(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi,
14945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                          shader_module const *vs, spirv_inst_iter entrypoint) {
14951b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
14965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14973a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto inputs = collect_interface_by_location(vs, entrypoint, spv::StorageClassInput, false);
14985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
149925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Build index by location
15005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
15015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
1502c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) {
1503c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            auto num_locations = get_locations_consumed_by_format(vi->pVertexAttributeDescriptions[i].format);
1504c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            for (auto j = 0u; j < num_locations; j++) {
1505c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes                attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
1506c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            }
1507c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        }
15085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_a = attribs.begin();
15115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_b = inputs.begin();
15121730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes    bool used = false;
15135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
15155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
15165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
15175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? 0 : it_a->first;
15185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? 0 : it_b->first.first;
15195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!a_at_end && (b_at_end || a_first < b_first)) {
15205b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski            if (!used && log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
15215b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski                                 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1522bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "Vertex attribute at location %d not consumed by vertex shader", a_first)) {
15231b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip = true;
15245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15251730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = false;
15265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_a++;
15275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (!b_at_end && (a_at_end || b_first < a_first)) {
15281b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
15291b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Vertex shader consumes input at location %d but not provided",
15301b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            b_first);
15315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
15325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
15335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned attrib_type = get_format_type(it_a->second->format);
15345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
15355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
153625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
1537f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            if (!(attrib_type & input_type)) {
15381b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
15391b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
15401b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Attribute type of `%s` at location %d does not match vertex shader input type of `%s`",
15411b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                string_VkFormat(it_a->second->format), a_first, describe_type(vs, it_b->second.type_id).c_str());
15425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
154425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
15451730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = true;
15465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
15475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15501b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
15515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1553edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_fs_outputs_against_render_pass(debug_report_data *report_data, shader_module const *fs,
15548da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    spirv_inst_iter entrypoint, VkRenderPassCreateInfo const *rpci,
15558da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    uint32_t subpass_index) {
1556025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    std::map<uint32_t, VkFormat> color_attachments;
15578da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    auto subpass = rpci->pSubpasses[subpass_index];
15588da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    for (auto i = 0u; i < subpass.colorAttachmentCount; ++i) {
1559d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        uint32_t attachment = subpass.pColorAttachments[i].attachment;
1560cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == VK_ATTACHMENT_UNUSED) continue;
1561d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        if (rpci->pAttachments[attachment].format != VK_FORMAT_UNDEFINED) {
1562d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis            color_attachments[i] = rpci->pAttachments[attachment].format;
1563025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        }
1564025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    }
1565025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
15661b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
15675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
156825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: dual source blend index (spv::DecIndex, zero if not provided)
15695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15703a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto outputs = collect_interface_by_location(fs, entrypoint, spv::StorageClassOutput, false);
15715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1572025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_a = outputs.begin();
1573025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_b = color_attachments.begin();
15745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
157525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk attachment list and outputs together
1576025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
1577025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    while ((outputs.size() > 0 && it_a != outputs.end()) || (color_attachments.size() > 0 && it_b != color_attachments.end())) {
1578025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool a_at_end = outputs.size() == 0 || it_a == outputs.end();
1579025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool b_at_end = color_attachments.size() == 0 || it_b == color_attachments.end();
15805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1581025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        if (!a_at_end && (b_at_end || it_a->first.first < it_b->first)) {
15821b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
15831b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
15841b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "fragment shader writes to output location %d with no matching attachment", it_a->first.first);
1585025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1586025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        } else if (!b_at_end && (a_at_end || it_a->first.first > it_b->first)) {
15871b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
15881b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by fragment shader", it_b->first);
1589025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
15905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1591025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned output_type = get_fundamental_type(fs, it_a->second.type_id);
1592025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned att_type = get_format_type(it_b->second);
15935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
159425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
1595f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            if (!(output_type & att_type)) {
15961b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
15971b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
15981b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Attachment %d of type `%s` does not match fragment shader output type of `%s`", it_b->first,
15991b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                string_VkFormat(it_b->second), describe_type(fs, it_a->second.type_id).c_str());
16005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
16015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
160225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
1603025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1604025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
16055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16081b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
16095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
161125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// For some analyses, we need to know about all ids referenced by the static call tree of a particular entrypoint. This is
161225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// important for identifying the set of shader resources actually used by an entrypoint, for example.
161325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
161425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//  - NOT the shader input/output interfaces.
161525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//
161625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
161725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// converting parts of this to be generated from the machine-readable spec instead.
16183a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbesstatic std::unordered_set<uint32_t> mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint) {
16193a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::unordered_set<uint32_t> ids;
16205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_set<uint32_t> worklist;
16215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    worklist.insert(entrypoint.word(2));
16225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!worklist.empty()) {
16245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id_iter = worklist.begin();
16255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id = *id_iter;
16265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        worklist.erase(id_iter);
16275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
16295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn == src->end()) {
163025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // ID is something we didn't collect in build_def_index. that's OK -- we'll stumble across all kinds of things here
163125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // that we may not care about.
16325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            continue;
16335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
163525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Try to add to the output set
16365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!ids.insert(id).second) {
1637cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            continue;  // If we already saw this id, we don't want to walk it again.
16385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
1641cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
1642cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Scan whole body of the function, enlisting anything interesting
1643cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1644cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    switch (insn.opcode()) {
1645cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpLoad:
1646cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicLoad:
1647cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicExchange:
1648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchange:
1649cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchangeWeak:
1650cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIIncrement:
1651cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIDecrement:
1652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIAdd:
1653cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicISub:
1654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMin:
1655cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMin:
1656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMax:
1657cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMax:
1658cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicAnd:
1659cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicOr:
1660cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicXor:
1661cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // ptr
1662cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpStore:
1664cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicStore:
1665cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // ptr
1666cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1667cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAccessChain:
1668cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpInBoundsAccessChain:
1669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // base ptr
1670cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1671cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpSampledImage:
1672cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleImplicitLod:
1673cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleExplicitLod:
1674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefImplicitLod:
1675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefExplicitLod:
1676cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjImplicitLod:
1677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjExplicitLod:
1678cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefImplicitLod:
1679cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefExplicitLod:
1680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageFetch:
1681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageGather:
1682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageDrefGather:
1683cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageRead:
1684cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImage:
1685cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryFormat:
1686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryOrder:
1687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySizeLod:
1688cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySize:
1689cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLod:
1690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLevels:
1691cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySamples:
1692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleImplicitLod:
1693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleExplicitLod:
1694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefImplicitLod:
1695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefExplicitLod:
1696cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjImplicitLod:
1697cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjExplicitLod:
1698cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefImplicitLod:
1699cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefExplicitLod:
1700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseFetch:
1701cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseGather:
1702cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseDrefGather:
1703cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageTexelPointer:
1704cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // Image or sampled image
1705cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1706cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageWrite:
1707cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // Image -- different operand order to above
1708cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1709cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpFunctionCall:
1710cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 3; i < insn.len(); i++) {
1711cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // fn itself, and all args
1712cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1713cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
17145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1715cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpExtInst:
1716cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 5; i < insn.len(); i++) {
1717cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // Operands to ext inst
1718cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1719cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
17205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
17215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
1722cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
17235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17253a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
17263a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return ids;
17275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1729edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_block_against_pipeline(debug_report_data *report_data,
1730416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                          std::vector<VkPushConstantRange> const *push_constant_ranges,
17315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          shader_module const *src, spirv_inst_iter type,
17325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          VkShaderStageFlagBits stage) {
17331b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
17345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
173525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off ptrs etc
17365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    type = get_struct_type(src, type, false);
17375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(type != src->end());
17385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
173925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate directly off the offsets. this isn't quite correct for arrays and matrices, but is a good first step.
174025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: arrays, matrices, weird sizes
17415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
17425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
17435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationOffset) {
17445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned offset = insn.word(4);
1745cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto size = 4;  // Bytes; TODO: calculate this based on the type
17465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                bool found_range = false;
1748416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                for (auto const &range : *push_constant_ranges) {
17495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (range.offset <= offset && range.offset + range.size >= offset + size) {
17505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        found_range = true;
17515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if ((range.stageFlags & stage) == 0) {
17531b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
17541b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            __LINE__, SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC",
17551b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            "Push constant range covering variable starting at "
17561b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            "offset %u not accessible from stage %s",
17571b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            offset, string_VkShaderStageFlagBits(stage));
17585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
17595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        break;
17615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
17625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
17635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!found_range) {
17651b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
17661b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    __LINE__, SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
17671b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    "Push constant range covering variable starting at "
17681b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    "offset %u not declared in layout",
17691b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    offset);
17705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
17715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17751b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
17765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1778edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_usage(debug_report_data *report_data,
1779416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                         std::vector<VkPushConstantRange> const *push_constant_ranges, shader_module const *src,
17805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                         std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
17811b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
17825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
17845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto def_insn = src->get_def(id);
17855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
17861b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= validate_push_constant_block_against_pipeline(report_data, push_constant_ranges, src,
1787416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                                  src->get_def(def_insn.word(1)), stage);
17885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17911b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
17925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1794fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis// For given pipelineLayout verify that the set_layout_node at slot.first
1795fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis//  has the requested binding at slot.second and return ptr to that binding
1796bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkDescriptorSetLayoutBinding const *get_descriptor_binding(PIPELINE_LAYOUT_NODE const *pipelineLayout,
1797bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  descriptor_slot_t slot) {
1798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pipelineLayout) return nullptr;
17995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1800cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (slot.first >= pipelineLayout->set_layouts.size()) return nullptr;
18015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1802416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    return pipelineLayout->set_layouts[slot.first]->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
18035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Check object status for selected flag state
180651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool validate_status(layer_data *dev_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
18074f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            const char *fail_msg, UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
18083d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (!(pNode->status & status_mask)) {
18094f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        char const *const message = validation_error_map[msg_code];
181051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
18119b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(pNode->commandBuffer), __LINE__, msg_code, "DS", "command buffer object 0x%p: %s. %s.",
18129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       pNode->commandBuffer, fail_msg, message);
18135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1814e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
18155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Retrieve pipeline node ptr for given pipeline object
181851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_STATE *getPipelineState(layer_data const *dev_data, VkPipeline pipeline) {
181951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineMap.find(pipeline);
182051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineMap.end()) {
1821ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        return nullptr;
18225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1823ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    return it->second;
18245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisRENDER_PASS_STATE *GetRenderPassState(layer_data const *dev_data, VkRenderPass renderpass) {
182751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->renderPassMap.find(renderpass);
182851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->renderPassMap.end()) {
182916387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes        return nullptr;
183016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes    }
1831fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    return it->second.get();
183216387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes}
183316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes
18349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFRAMEBUFFER_STATE *GetFramebufferState(const layer_data *dev_data, VkFramebuffer framebuffer) {
183551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->frameBufferMap.find(framebuffer);
183651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->frameBufferMap.end()) {
1837f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes        return nullptr;
1838f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes    }
183904861caca7eb93a5241b164e8480bb93c826902cTobin Ehlis    return it->second.get();
1840f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes}
1841f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes
18429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSetLayout const *GetDescriptorSetLayout(layer_data const *dev_data, VkDescriptorSetLayout dsLayout) {
184351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->descriptorSetLayoutMap.find(dsLayout);
184451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->descriptorSetLayoutMap.end()) {
184511f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes        return nullptr;
184611f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    }
184711f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    return it->second;
184811f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes}
184911f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes
185051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_LAYOUT_NODE const *getPipelineLayout(layer_data const *dev_data, VkPipelineLayout pipeLayout) {
185151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineLayoutMap.find(pipeLayout);
185251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineLayoutMap.end()) {
18534a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes        return nullptr;
18544a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    }
18554a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    return &it->second;
18564a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes}
18574a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes
1858e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if for a given PSO, the given state enum is dynamic, else return false
18594c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool isDynamic(const PIPELINE_STATE *pPipeline, const VkDynamicState state) {
18605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) {
18615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
1862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) return true;
18635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1865e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
18665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate state stored as flags at time of draw call
18694f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayesstatic bool validate_draw_state_flags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe, bool indexed,
18704f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                      UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
18719c4006684a13db43f0dbc8d0015a9ef34872ca09Chris Forbes    bool result = false;
1872ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipe->graphicsPipelineCI.pInputAssemblyState &&
1873ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        ((pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
1874ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         (pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP))) {
18753d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_LINE_WIDTH_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18764f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic line width state not set for this command buffer", msg_code);
18773d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
187845824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pRasterizationState &&
187945824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pRasterizationState->depthBiasEnable == VK_TRUE)) {
18803d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BIAS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18814f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bias state not set for this command buffer", msg_code);
18823d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
18833d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->blendConstantsEnabled) {
18843d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_BLEND_CONSTANTS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18854f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic blend constants state not set for this command buffer", msg_code);
18863d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
188745824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
188845824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE)) {
18893d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BOUNDS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18904f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bounds state not set for this command buffer", msg_code);
18913d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
189245824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
189345824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->stencilTestEnable == VK_TRUE)) {
18943d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18954f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil read mask state not set for this command buffer", msg_code);
18963d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18974f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil write mask state not set for this command buffer", msg_code);
18983d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18994f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil reference state not set for this command buffer", msg_code);
19003d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
19011c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (indexed) {
19023d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_INDEX_BUFFER_BOUND, VK_DEBUG_REPORT_ERROR_BIT_EXT,
19034f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Index buffer object not bound to this command buffer when Indexed Draw attempted", msg_code);
19043d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
19054f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes
19065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
19075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
19085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify attachment reference compatibility according to spec
19105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this
19115ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski//  If both AttachmentReference arrays have requested index, check their corresponding AttachmentDescriptions
19125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//   to make sure that format and samples counts match.
19135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If not, they are not compatible.
19145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary,
19155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments,
19165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentReference *pSecondary, const uint32_t secondaryCount,
19175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentDescription *pSecondaryAttachments) {
1918e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    // Check potential NULL cases first to avoid nullptr issues later
1919e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    if (pPrimary == nullptr) {
1920e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        if (pSecondary == nullptr) {
1921e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis            return true;
1922e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        }
1923e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
1924e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    } else if (pSecondary == nullptr) {
1925e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
1926e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    }
1927cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (index >= primaryCount) {  // Check secondary as if primary is VK_ATTACHMENT_UNUSED
1928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pSecondary[index].attachment) return true;
1929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (index >= secondaryCount) {  // Check primary as if secondary is VK_ATTACHMENT_UNUSED
1930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pPrimary[index].attachment) return true;
1931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // Format and sample count must match
19325ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) && (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
19335ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return true;
19345ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        } else if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) || (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
19355ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return false;
19365ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        }
19375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((pPrimaryAttachments[pPrimary[index].attachment].format ==
19385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].format) &&
19395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (pPrimaryAttachments[pPrimary[index].attachment].samples ==
19405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].samples))
19415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return true;
19425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
19435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Format and sample counts didn't match
19445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
19455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1946a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// TODO : Scrub verify_renderpass_compatibility() and validateRenderPassCompatibility() and unify them and/or share code
1947266231a5421564c314f6b5d5bd3fed26fd389484Chris Forbes// For given primary RenderPass object and secondary RenderPassCreateInfo, verify that they're compatible
194851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verify_renderpass_compatibility(const layer_data *dev_data, const VkRenderPassCreateInfo *primaryRPCI,
19498da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                            const VkRenderPassCreateInfo *secondaryRPCI, string &errorMsg) {
19505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
1951c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
19525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
19535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses.";
19545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
19555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
19565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
19575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t spIndex = 0;
19585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) {
19595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible
19605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
19615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
19625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount);
19635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) {
19645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount,
19655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments,
19665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
1967c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
19685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
19695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
19705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
19715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments,
19725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         primaryColorCount, primaryRPCI->pAttachments,
19735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryRPCI->pSubpasses[spIndex].pResolveAttachments,
19745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryColorCount, secondaryRPCI->pAttachments)) {
1975c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
19765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
19775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
19785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
19795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
19805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
1981fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
1982bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (!attachment_references_compatible(0, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 1,
1983bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
1984fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes                                              1, secondaryRPCI->pAttachments)) {
1985c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes            stringstream errorStr;
1986fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorStr << "depth/stencil attachments of subpass index " << spIndex << " are not compatible.";
1987fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorMsg = errorStr.str();
1988fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            return false;
1989fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes        }
1990fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
19915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
19925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
19935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount);
19945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < inputMax; ++i) {
19951e49a9dd0518c3cd335dd040218aa9c25d7cb600Tobin Ehlis            if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryInputCount,
19965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments,
19971e49a9dd0518c3cd335dd040218aa9c25d7cb600Tobin Ehlis                                                  secondaryInputCount, secondaryRPCI->pAttachments)) {
1998c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
19995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible.";
20005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
20015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
20025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return true;
20065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2008397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
2009397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// pipelineLayout[layoutIndex]
201012b7fc342b53fbdd399aae4a85959e37685936acChris Forbesstatic bool verify_set_layout_compatibility(const cvdescriptorset::DescriptorSet *descriptor_set,
201169b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            PIPELINE_LAYOUT_NODE const *pipeline_layout, const uint32_t layoutIndex,
201269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            string &errorMsg) {
2013416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto num_sets = pipeline_layout->set_layouts.size();
20149b5d124aff50234cb0450e1b805baef577c90d83Tobin Ehlis    if (layoutIndex >= num_sets) {
2015c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
201669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        errorStr << "VkPipelineLayout (" << pipeline_layout->layout << ") only contains " << num_sets
201769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << " setLayouts corresponding to sets 0-" << num_sets - 1 << ", but you're attempting to bind set to index "
201869b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << layoutIndex;
20195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
20205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
20215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2022416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto layout_node = pipeline_layout->set_layouts[layoutIndex];
20231c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    return descriptor_set->IsCompatible(layout_node, &errorMsg);
20245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that data for each specialization entry is fully contained within the buffer.
2027edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_specialization_offsets(debug_report_data *report_data, VkPipelineShaderStageCreateInfo const *info) {
20281b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
20295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkSpecializationInfo const *spec = info->pSpecializationInfo;
20315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (spec) {
20335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto i = 0u; i < spec->mapEntryCount; i++) {
2034315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // TODO: This is a good place for VALIDATION_ERROR_1360060a.
20355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
20361b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
2037315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                VALIDATION_ERROR_1360060c, "SC",
20381b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Specialization entry %u (for constant id %u) references memory outside provided "
20391b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER
20401b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                " bytes provided). %s.",
20411b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
20421b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize,
2043315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_1360060c]);
20445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20481b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
20495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2051bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool descriptor_type_match(shader_module const *module, uint32_t type_id, VkDescriptorType descriptor_type,
2052bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  unsigned &descriptor_count) {
20535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto type = module->get_def(type_id);
20545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20551b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes    descriptor_count = 1;
20561b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes
205725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off any array or ptrs. Where we remove array levels, adjust the  descriptor count for each dimension.
20585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) {
20597b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        if (type.opcode() == spv::OpTypeArray) {
20607b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            descriptor_count *= get_constant_value(module, type.word(3));
20617b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(2));
2062bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
20637b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(3));
20647b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        }
20655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type.opcode()) {
2068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
2069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (auto insn : *module) {
2070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
2071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (insn.word(2) == spv::DecorationBlock) {
2072cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
2073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
2074cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    } else if (insn.word(2) == spv::DecorationBufferBlock) {
2075cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
2076cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
2077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
20785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
20795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2081cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Invalid
2082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
2083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
20845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
2086cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER || descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
20875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2088cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
2089cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) {
2090cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
2091cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // buffer descriptor doesn't really provide one. Allow this slight mismatch.
2092cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto image_type = module->get_def(type.word(2));
2093cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = image_type.word(3);
2094cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto sampled = image_type.word(7);
2095cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return dim == spv::DimBuffer && sampled == 1;
2096cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
2097cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
20985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2099cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage: {
2100cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
2101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // SPIRV for Vulkan requires that sampled be 1 or 2 -- leaving the decision to runtime is unacceptable.
2102cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto dim = type.word(3);
2103cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto sampled = type.word(7);
21045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2105cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (dim == spv::DimSubpassData) {
2106cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
2107cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (dim == spv::DimBuffer) {
2108cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (sampled == 1) {
2109cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
2110cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
2111cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
2112cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
2113cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (sampled == 1) {
2114cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
2115cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                       descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
21165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
2117cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
21185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
21195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
21205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2121cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
2122cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
2123cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;  // Mismatch
21245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
21255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21274110a6be7a8a287d459475926985f71c27d01298Chris Forbesstatic bool require_feature(debug_report_data *report_data, VkBool32 feature, char const *feature_name) {
2128a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    if (!feature) {
21295b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2130cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
2131cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "Shader requires VkPhysicalDeviceFeatures::%s but is not "
2132cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "enabled on the device",
2133a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes                    feature_name)) {
21341b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            return true;
2135a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2136a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2137a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
21381b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return false;
2139a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2140a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
214159e12b842592a05706886ab852b767ba251d9467Chris Forbesstatic bool require_extension(debug_report_data *report_data, bool extension, char const *extension_name) {
21427b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes    if (!extension) {
21435b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
21447b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
21457b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    "Shader requires extension %s but is not "
21467b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    "enabled on the device",
21477b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    extension_name)) {
21481b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            return true;
21497b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes        }
21507b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes    }
21517b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes
21521b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return false;
21537b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes}
21547b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes
2155ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_shader_capabilities(layer_data *dev_data, shader_module const *src) {
21561b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
2157a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2158ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto report_data = dev_data->report_data;
2159ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto const & enabledFeatures = dev_data->enabled_features;
2160ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes
2161a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    struct CapabilityInfo {
2162a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        char const *name;
2163a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        VkBool32 const VkPhysicalDeviceFeatures::*feature;
2164bdaffa5403b494e78a9b461182e2e6360c2b775cChris Forbes        bool const DeviceExtensions::*extension;
2165a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    };
2166a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes
2167a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    using F = VkPhysicalDeviceFeatures;
2168bdaffa5403b494e78a9b461182e2e6360c2b775cChris Forbes    using E = DeviceExtensions;
2169a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes
2170a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    // clang-format off
2171a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    static const std::unordered_map<uint32_t, CapabilityInfo> capabilities = {
2172a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        // Capabilities always supported by a Vulkan 1.0 implementation -- no
2173a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        // feature bits.
2174a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityMatrix, {nullptr}},
2175a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityShader, {nullptr}},
2176a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityInputAttachment, {nullptr}},
2177a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySampled1D, {nullptr}},
2178a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityImage1D, {nullptr}},
2179a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySampledBuffer, {nullptr}},
2180a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityImageQuery, {nullptr}},
2181a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityDerivativeControl, {nullptr}},
2182a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes
2183a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        // Capabilities that are optionally supported, but require a feature to
2184a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        // be enabled on the device
2185a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityGeometry, {"geometryShader", &F::geometryShader}},
2186a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityTessellation, {"tessellationShader", &F::tessellationShader}},
2187a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityFloat64, {"shaderFloat64", &F::shaderFloat64}},
2188a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityInt64, {"shaderInt64", &F::shaderInt64}},
2189a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityTessellationPointSize, {"shaderTessellationAndGeometryPointSize", &F::shaderTessellationAndGeometryPointSize}},
2190a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityGeometryPointSize, {"shaderTessellationAndGeometryPointSize", &F::shaderTessellationAndGeometryPointSize}},
2191a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityImageGatherExtended, {"shaderImageGatherExtended", &F::shaderImageGatherExtended}},
2192a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageImageMultisample, {"shaderStorageImageMultisample", &F::shaderStorageImageMultisample}},
2193a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityUniformBufferArrayDynamicIndexing, {"shaderUniformBufferArrayDynamicIndexing", &F::shaderUniformBufferArrayDynamicIndexing}},
2194a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySampledImageArrayDynamicIndexing, {"shaderSampledImageArrayDynamicIndexing", &F::shaderSampledImageArrayDynamicIndexing}},
2195a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageBufferArrayDynamicIndexing, {"shaderStorageBufferArrayDynamicIndexing", &F::shaderStorageBufferArrayDynamicIndexing}},
2196a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageImageArrayDynamicIndexing, {"shaderStorageImageArrayDynamicIndexing", &F::shaderStorageBufferArrayDynamicIndexing}},
2197a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityClipDistance, {"shaderClipDistance", &F::shaderClipDistance}},
2198a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityCullDistance, {"shaderCullDistance", &F::shaderCullDistance}},
2199a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityImageCubeArray, {"imageCubeArray", &F::imageCubeArray}},
2200a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySampleRateShading, {"sampleRateShading", &F::sampleRateShading}},
2201a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySparseResidency, {"shaderResourceResidency", &F::shaderResourceResidency}},
2202a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityMinLod, {"shaderResourceMinLod", &F::shaderResourceMinLod}},
2203a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySampledCubeArray, {"imageCubeArray", &F::imageCubeArray}},
2204a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityImageMSArray, {"shaderStorageImageMultisample", &F::shaderStorageImageMultisample}},
2205a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageImageExtendedFormats, {"shaderStorageImageExtendedFormats", &F::shaderStorageImageExtendedFormats}},
2206a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityInterpolationFunction, {"sampleRateShading", &F::sampleRateShading}},
2207a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageImageReadWithoutFormat, {"shaderStorageImageReadWithoutFormat", &F::shaderStorageImageReadWithoutFormat}},
2208a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageImageWriteWithoutFormat, {"shaderStorageImageWriteWithoutFormat", &F::shaderStorageImageWriteWithoutFormat}},
2209a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityMultiViewport, {"multiViewport", &F::multiViewport}},
2210a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes
2211a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        // Capabilities that require an extension
2212d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilityDrawParameters, {VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, nullptr, &E::vk_khr_shader_draw_parameters}},
2213d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilityGeometryShaderPassthroughNV, {VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME, nullptr, &E::vk_nv_geometry_shader_passthrough}},
2214d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilitySampleMaskOverrideCoverageNV, {VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME, nullptr, &E::vk_nv_sample_mask_override_coverage}},
2215d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilityShaderViewportIndexLayerNV, {VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME, nullptr, &E::vk_nv_viewport_array2}},
2216d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilityShaderViewportMaskNV, {VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME, nullptr, &E::vk_nv_viewport_array2}},
2217d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilitySubgroupBallotKHR, {VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, nullptr, &E::vk_ext_shader_subgroup_ballot }},
2218d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilitySubgroupVoteKHR, {VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, nullptr, &E::vk_ext_shader_subgroup_vote }},
2219a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    };
2220a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    // clang-format on
2221a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes
2222a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    for (auto insn : *src) {
2223a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        if (insn.opcode() == spv::OpCapability) {
2224a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes            auto it = capabilities.find(insn.word(1));
2225a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes            if (it != capabilities.end()) {
2226a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes                if (it->second.feature) {
2227a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes                    skip |= require_feature(report_data, enabledFeatures.*(it->second.feature), it->second.name);
2228a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes                }
2229a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes                if (it->second.extension) {
2230a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski                    skip |= require_extension(report_data, dev_data->extensions.*(it->second.extension), it->second.name);
2231a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes                }
2232a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            }
2233a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2234a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2235a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
22361b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
2237a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2238a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2239b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbesstatic uint32_t descriptor_type_to_reqs(shader_module const *module, uint32_t type_id) {
22402aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    auto type = module->get_def(type_id);
22412aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes
22422aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    while (true) {
22432aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        switch (type.opcode()) {
2244cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
2245cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
2246cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(2));
2247cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
2249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(3));
2250cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2251cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage: {
2252cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = type.word(3);
2253cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto arrayed = type.word(5);
2254cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto msaa = type.word(6);
2255cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
2256cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                switch (dim) {
2257cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim1D:
2258cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_1D;
2259cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim2D:
2260cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return (msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE) |
2261cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               (arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_2D);
2262cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim3D:
2263cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return DESCRIPTOR_REQ_VIEW_TYPE_3D;
2264cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimCube:
2265cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_CUBE;
2266cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimSubpassData:
2267cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
2268cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    default:  // buffer, etc.
2269cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return 0;
2270cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
22712aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes            }
2272cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
2273cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return 0;
22742aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        }
22752aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    }
2276b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes}
2277b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes
2278cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool validate_pipeline_shader_stage(
2279ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    layer_data *dev_data, VkPipelineShaderStageCreateInfo const *pStage, PIPELINE_STATE *pipeline,
2280ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    shader_module **out_module, spirv_inst_iter *out_entrypoint) {
22811b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
2282ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto module_it = dev_data->shaderModuleMap.find(pStage->module);
228369f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes    auto module = *out_module = module_it->second.get();
2284ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto report_data = dev_data->report_data;
228578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
22861b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    if (!module->has_valid_spirv) return false;
2287c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski
228825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the entrypoint
228978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    auto entrypoint = *out_entrypoint = find_entrypoint(module, pStage->pName, pStage->stage);
229078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    if (entrypoint == module->end()) {
22915b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2292315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    VALIDATION_ERROR_10600586, "SC", "No entrypoint found named `%s` for stage %s. %s.", pStage->pName,
2293315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    string_VkShaderStageFlagBits(pStage->stage), validation_error_map[VALIDATION_ERROR_10600586])) {
22941b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            return true;  // no point continuing beyond here, any analysis is just going to be garbage.
229578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
229678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
229778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
229825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate shader capabilities against enabled device features
22991b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    skip |= validate_shader_capabilities(dev_data, module);
230078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
230125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Mark accessible ids
23023a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto accessible_ids = mark_accessible_ids(module, entrypoint);
230378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
230425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor set layout against what the entrypoint actually uses
23053a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto descriptor_uses = collect_interface_by_descriptor_slot(report_data, module, accessible_ids);
230678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
23072e0eca3d6fad72a29ae072e3895e29a2d2d66476Tobin Ehlis    auto pipelineLayout = pipeline->pipeline_layout;
2308ed399f66e0512ef077d0e0a7cb903248726d2424Chris Forbes
23091b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    skip |= validate_specialization_offsets(report_data, pStage);
23101b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    skip |= validate_push_constant_usage(report_data, &pipelineLayout.push_constant_ranges, module, accessible_ids, pStage->stage);
231178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
231225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor use
231378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    for (auto use : descriptor_uses) {
231478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        // While validating shaders capture which slots are used by the pipeline
2315bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &reqs = pipeline->active_slots[use.first.first][use.first.second];
2316b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes        reqs = descriptor_req(reqs | descriptor_type_to_reqs(module, use.second.type_id));
231778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
231825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Verify given pipelineLayout has requested setLayout with requested binding
2319c8268861aaa8f9c47920065d6323e4609e5081b0Tobin Ehlis        const auto &binding = get_descriptor_binding(&pipelineLayout, use.first);
232078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        unsigned required_descriptor_count;
232178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
232278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        if (!binding) {
23231b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
23241b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
23251b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
23261b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str());
232778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (~binding->stageFlags & pStage->stage) {
23281b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
23291b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC",
23301b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Shader uses descriptor slot %u.%u (used "
23311b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "as type `%s`) but descriptor not "
23321b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "accessible from stage %s",
23331b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
23341b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            string_VkShaderStageFlagBits(pStage->stage));
2335bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else if (!descriptor_type_match(module, use.second.type_id, binding->descriptorType, required_descriptor_count)) {
23361b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
23371b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
23381b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Type mismatch on descriptor slot "
23391b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "%u.%u (used as type `%s`) but "
23401b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "descriptor of type %s",
23411b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
23421b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            string_VkDescriptorType(binding->descriptorType));
234378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (binding->descriptorCount < required_descriptor_count) {
23441b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
23451b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
23461b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
23471b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            required_descriptor_count, use.first.first, use.first.second,
23481b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            describe_type(module, use.second.type_id).c_str(), binding->descriptorCount);
234978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
235078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
235178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
235225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate use of input attachments against subpass structure
2353c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    if (pStage->stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
235412b7fc342b53fbdd399aae4a85959e37685936acChris Forbes        auto input_attachment_uses = collect_interface_by_input_attachment_index(module, accessible_ids);
2355c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2356c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto rpci = pipeline->render_pass_ci.ptr();
2357c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto subpass = pipeline->graphicsPipelineCI.subpass;
2358c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2359c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        for (auto use : input_attachment_uses) {
2360c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            auto input_attachments = rpci->pSubpasses[subpass].pInputAttachments;
2361bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto index = (input_attachments && use.first < rpci->pSubpasses[subpass].inputAttachmentCount)
2362bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             ? input_attachments[use.first].attachment
2363bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             : VK_ATTACHMENT_UNUSED;
2364c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2365c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            if (index == VK_ATTACHMENT_UNUSED) {
23661b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
23671b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_MISSING_INPUT_ATTACHMENT, "SC",
23681b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Shader consumes input attachment index %d but not provided in subpass", use.first);
2369f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            } else if (!(get_format_type(rpci->pAttachments[index].format) & get_fundamental_type(module, use.second.type_id))) {
23701b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |=
23711b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2372eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                            SHADER_CHECKER_INPUT_ATTACHMENT_TYPE_MISMATCH, "SC",
2373bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Subpass input attachment %u format of %s does not match type used in shader `%s`", use.first,
23741b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            string_VkFormat(rpci->pAttachments[index].format), describe_type(module, use.second.type_id).c_str());
2375eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes            }
2376c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        }
2377c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    }
2378c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
23791b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
238078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes}
238178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
2382a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis// Validate that the shaders used by the given pipeline and store the active_slots
2383a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis//  that are actually used by the pipeline into pPipeline->active_slots
2384ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_and_capture_pipeline_shader_state(layer_data *dev_data, PIPELINE_STATE *pPipeline) {
23856660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->graphicsPipelineCI.ptr();
23865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
23875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
23885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module *shaders[5];
23905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(shaders, 0, sizeof(shaders));
23915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter entrypoints[5];
23925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(entrypoints, 0, sizeof(entrypoints));
23931b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
23945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
23966660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes        auto pStage = &pCreateInfo->pStages[i];
239778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        auto stage_id = get_shader_stage_id(pStage->stage);
23981b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_pipeline_shader_stage(dev_data, pStage, pPipeline, &shaders[stage_id], &entrypoints[stage_id]);
23995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2401d5365427feb4a6c16371ecb651afa37b89dabd96Chris Forbes    // if the shader stages are no good individually, cross-stage validation is pointless.
24021b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    if (skip) return true;
2403b7476f4c4998ae20e579bd2d134667b71acdbf91Chris Forbes
2404ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto vi = pCreateInfo->pVertexInputState;
24055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
24071b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_vi_consistency(dev_data->report_data, vi);
24085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2410c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[vertex_stage] && shaders[vertex_stage]->has_valid_spirv) {
24111b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_vi_against_vs_inputs(dev_data->report_data, vi, shaders[vertex_stage], entrypoints[vertex_stage]);
24125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
24155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
24165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!shaders[producer] && producer != fragment_stage) {
24185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        producer++;
24195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        consumer++;
24205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
24235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(shaders[producer]);
2424c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        if (shaders[consumer] && shaders[consumer]->has_valid_spirv && shaders[producer]->has_valid_spirv) {
24251b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= validate_interface_between_stages(dev_data->report_data, shaders[producer], entrypoints[producer],
2426bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[producer], shaders[consumer], entrypoints[consumer],
2427bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[consumer]);
24285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            producer = consumer;
24305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
24315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2433c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[fragment_stage] && shaders[fragment_stage]->has_valid_spirv) {
24341b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_fs_outputs_against_render_pass(dev_data->report_data, shaders[fragment_stage], entrypoints[fragment_stage],
24358da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                        pPipeline->render_pass_ci.ptr(), pCreateInfo->subpass);
24365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24381b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
24395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
24405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2441ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_compute_pipeline(layer_data *dev_data, PIPELINE_STATE *pPipeline) {
24426660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->computePipelineCI.ptr();
244303857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
244403857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    shader_module *module;
244503857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    spirv_inst_iter entrypoint;
244603857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
2447ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    return validate_pipeline_shader_stage(dev_data, &pCreateInfo->stage, pPipeline, &module, &entrypoint);
244803857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes}
24495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Set node ptr for specified set or else NULL
24509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSet *GetSetNode(const layer_data *dev_data, VkDescriptorSet set) {
245151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto set_it = dev_data->setMap.find(set);
245251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (set_it == dev_data->setMap.end()) {
24535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
24545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2455104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return set_it->second;
24565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
24575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2458eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// For given pipeline, return number of MSAA samples, or one if MSAA disabled
24594c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic VkSampleCountFlagBits getNumSamples(PIPELINE_STATE const *pipe) {
2460ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    if (pipe->graphicsPipelineCI.pMultisampleState != NULL &&
2461ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pipe->graphicsPipelineCI.pMultisampleState->sType) {
2462eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        return pipe->graphicsPipelineCI.pMultisampleState->rasterizationSamples;
2463eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2464eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return VK_SAMPLE_COUNT_1_BIT;
2465eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2466eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
2467bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void list_bits(std::ostream &s, uint32_t bits) {
2468b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    for (int i = 0; i < 32 && bits; i++) {
2469b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        if (bits & (1 << i)) {
2470b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            s << i;
2471b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            bits &= ~(1 << i);
2472b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (bits) {
2473b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                s << ",";
2474b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            }
2475b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        }
2476b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    }
2477b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes}
2478b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
2479eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// Validate draw-time state related to the PSO
248051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidatePipelineDrawtimeState(layer_data const *dev_data, LAST_BOUND_STATE const &state, const GLOBAL_CB_NODE *pCB,
24814c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                          PIPELINE_STATE const *pPipeline) {
24823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
248329d196e071b2dc1db47702085469396f2b956820Chris Forbes
2484d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen    // Verify vertex binding
248529d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (pPipeline->vertexBindingDescriptions.size() > 0) {
248629d196e071b2dc1db47702085469396f2b956820Chris Forbes        for (size_t i = 0; i < pPipeline->vertexBindingDescriptions.size(); i++) {
2487312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            auto vertex_binding = pPipeline->vertexBindingDescriptions[i].binding;
2488312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            if ((pCB->currentDrawData.buffers.size() < (vertex_binding + 1)) ||
2489312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis                (pCB->currentDrawData.buffers[vertex_binding] == VK_NULL_HANDLE)) {
24903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
2491df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
24929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2493cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "The Pipeline State Object (0x%" PRIxLEAST64
2494cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            ") expects that this Command Buffer's vertex binding Index %u "
2495cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct "
2496cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "at index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
24979b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(state.pipeline_state->pipeline), vertex_binding, i, vertex_binding);
249829d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
249929d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
250029d196e071b2dc1db47702085469396f2b956820Chris Forbes    } else {
250158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        if (!pCB->currentDrawData.buffers.empty() && !pCB->vertex_buffer_used) {
25023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
25039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCB->commandBuffer), __LINE__,
25049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
25053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Vertex buffers are bound to command buffer (0x%p"
25063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") but no vertex buffers are attached to this Pipeline State Object (0x%" PRIxLEAST64 ").",
25079b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pCB->commandBuffer, HandleToUint64(state.pipeline_state->pipeline));
250829d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
250929d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
251029d196e071b2dc1db47702085469396f2b956820Chris Forbes    // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
251129d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip check if rasterization is disabled or there is no viewport.
251229d196e071b2dc1db47702085469396f2b956820Chris Forbes    if ((!pPipeline->graphicsPipelineCI.pRasterizationState ||
251329d196e071b2dc1db47702085469396f2b956820Chris Forbes         (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) &&
251429d196e071b2dc1db47702085469396f2b956820Chris Forbes        pPipeline->graphicsPipelineCI.pViewportState) {
251529d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
251629d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
2517b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
251829d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynViewport) {
2519b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredViewportsMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->viewportCount) - 1;
2520b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingViewportMask = ~pCB->viewportMask & requiredViewportsMask;
2521b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingViewportMask) {
2522b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2523b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic viewport(s) ";
2524b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingViewportMask);
2525d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetViewport().";
25263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
25273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
252829d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
252929d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
2530b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
253129d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynScissor) {
2532b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredScissorMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->scissorCount) - 1;
2533b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingScissorMask = ~pCB->scissorMask & requiredScissorMask;
2534b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingScissorMask) {
2535b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2536b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic scissor(s) ";
2537b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingScissorMask);
2538d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetScissor().";
25393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
25403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
254129d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
254229d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
254329d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
254429d196e071b2dc1db47702085469396f2b956820Chris Forbes
254529d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Verify that any MSAA request in PSO matches sample# in bound FB
254629d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip the check if rasterization is disabled.
254729d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
254829d196e071b2dc1db47702085469396f2b956820Chris Forbes        (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
254929d196e071b2dc1db47702085469396f2b956820Chris Forbes        VkSampleCountFlagBits pso_num_samples = getNumSamples(pPipeline);
255029d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (pCB->activeRenderPass) {
2551fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes            auto const render_pass_info = pCB->activeRenderPass->createInfo.ptr();
255229d196e071b2dc1db47702085469396f2b956820Chris Forbes            const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass];
255329d196e071b2dc1db47702085469396f2b956820Chris Forbes            uint32_t i;
255476957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            unsigned subpass_num_samples = 0;
25550a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
255629d196e071b2dc1db47702085469396f2b956820Chris Forbes            for (i = 0; i < subpass_desc->colorAttachmentCount; i++) {
255776957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pColorAttachments[i].attachment;
255876957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                if (attachment != VK_ATTACHMENT_UNUSED)
255976957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                    subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
256029d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
25610a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
256276957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            if (subpass_desc->pDepthStencilAttachment &&
256376957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
256476957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
256576957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
256629d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
2567eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
25680dc3fd4e57b8531638781daa01a2fb5d1048a6fbJamie Madill            if (subpass_num_samples && static_cast<unsigned>(pso_num_samples) != subpass_num_samples) {
25693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
25709b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
25719b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Num samples mismatch! At draw-time in Pipeline (0x%" PRIxLEAST64
25729b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                ") with %u samples while current RenderPass (0x%" PRIxLEAST64 ") w/ %u samples!",
25739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), pso_num_samples,
25749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pCB->activeRenderPass->renderPass), subpass_num_samples);
2575eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young            }
257629d196e071b2dc1db47702085469396f2b956820Chris Forbes        } else {
25773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
25789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
25793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "No active render pass found at draw-time in Pipeline (0x%" PRIxLEAST64 ")!",
25809b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline));
2581eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        }
2582eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2583528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    // Verify that PSO creation renderPass is compatible with active renderPass
2584528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    if (pCB->activeRenderPass) {
2585528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        std::string err_string;
2586a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if ((pCB->activeRenderPass->renderPass != pPipeline->graphicsPipelineCI.renderPass) &&
258751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(), pPipeline->render_pass_ci.ptr(),
2588528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                                             err_string)) {
2589528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            // renderPass that PSO was created with must be compatible with active renderPass that PSO is being used with
25903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
25919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
25929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "At Draw time the active render pass (0x%" PRIxLEAST64
25939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            ") is incompatible w/ gfx pipeline "
25949b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "(0x%" PRIxLEAST64 ") that was created w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
25959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->activeRenderPass->renderPass), HandleToUint64(pPipeline->pipeline),
25969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->graphicsPipelineCI.renderPass), err_string.c_str());
2597528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        }
2598c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes
2599c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        if (pPipeline->graphicsPipelineCI.subpass != pCB->activeSubpass) {
26003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
26019b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
26029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Pipeline was built for subpass %u but used in subpass %u", pPipeline->graphicsPipelineCI.subpass,
26033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            pCB->activeSubpass);
2604c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        }
2605528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    }
260629d196e071b2dc1db47702085469396f2b956820Chris Forbes    // TODO : Add more checks here
260729d196e071b2dc1db47702085469396f2b956820Chris Forbes
26083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
2609eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2610eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
26115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate overall state at the time of a draw call
261251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const bool indexed,
26134f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              const VkPipelineBindPoint bind_point, const char *function,
26144f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
2615e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
26161c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_node->lastBound[bind_point];
26174c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
261822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    if (nullptr == pPipe) {
261922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        result |= log_msg(
2620df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
26219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            HandleToUint64(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_PIPELINE, "DS",
262222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            "At Draw/Dispatch time no valid VkPipeline is bound! This is illegal. Please bind one with vkCmdBindPipeline().");
262322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        // Early return as any further checks below will be busted w/o a pipeline
2624cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (result) return true;
262522fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
26263d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // First check flag states
26271c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point)
262851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        result = validate_draw_state_flags(dev_data, cb_node, pPipe, indexed, msg_code);
26297a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis
26305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Now complete other state checks
263169b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
263222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        string errorString;
263369b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        auto pipeline_layout = pPipe->pipeline_layout;
2634169c4506062f06d6676eb4da3c9e0437d1d9d659Chris Forbes
26351c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
26361c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
263722fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            // If valid set is not bound throw an error
263822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
26399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                result |=
26409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
26419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_node->commandBuffer), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS",
26429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "VkPipeline 0x%" PRIxLEAST64 " uses set #%u but that set is not bound.",
26439b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipe->pipeline), setIndex);
264412b7fc342b53fbdd399aae4a85959e37685936acChris Forbes            } else if (!verify_set_layout_compatibility(state.boundDescriptorSets[setIndex], &pipeline_layout, setIndex,
264569b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                                        errorString)) {
264669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                // Set is bound but not compatible w/ overlapping pipeline_layout from PSO
264771511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                VkDescriptorSet setHandle = state.boundDescriptorSets[setIndex]->GetSet();
264822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                result |=
264951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
26509b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(setHandle), __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
2651414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            "VkDescriptorSet (0x%" PRIxLEAST64
2652414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") bound as set #%u is not compatible with overlapping VkPipelineLayout 0x%" PRIxLEAST64 " due to: %s",
26539b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(setHandle), setIndex, HandleToUint64(pipeline_layout.layout), errorString.c_str());
2654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {  // Valid set is bound and layout compatible, validate that it's updated
265522fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Pull the set node
26561c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
26577433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                // Validate the draw-time state for this descriptor set
26587433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                std::string err_str;
26590db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                if (!descriptor_set->ValidateDrawState(set_binding_pair.second, state.dynamicOffsets[setIndex], cb_node, function,
26600db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                                                       &err_str)) {
26611c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    auto set = descriptor_set->GetSet();
26620db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                    result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
26639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                      VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(set), __LINE__,
26649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                      DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
26650db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                                      "Descriptor set 0x%" PRIxLEAST64 " encountered the following validation error at %s time: %s",
26669b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                      HandleToUint64(set), function, err_str.c_str());
26677433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                }
26685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
266922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        }
267022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
2671eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
2672eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    // Check general pipeline state that needs to be validated at drawtime
267351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) result |= ValidatePipelineDrawtimeState(dev_data, state, cb_node, pPipe);
2674eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
26755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
26765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
26775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
267851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const VkPipelineBindPoint bind_point) {
26791c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_state->lastBound[bind_point];
2680ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
2681ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
26821c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
26831c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
2684ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Pull the set node
26851c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
2686ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Bind this set and its active descriptor resources to the command buffer
26871c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->BindCommandBuffer(cb_state, set_binding_pair.second);
26887433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis            // For given active slots record updated images & buffers
26891c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->GetStorageUpdates(set_binding_pair.second, &cb_state->updateBuffers, &cb_state->updateImages);
2690ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis        }
2691ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    }
269258b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (pPipe->vertexBindingDescriptions.size() > 0) {
269358b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        cb_state->vertex_buffer_used = true;
269458b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
2695ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis}
2696ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis
2697a27508babf63d50aea75883a3702979193c23683Mark Young// Validate HW line width capabilities prior to setting requested line width.
269806727c7f56d1080aff506a9ae1ae9d8c174b3e9dMark Lobodzinskistatic bool verifyLineWidth(layer_data *dev_data, DRAW_STATE_ERROR dsError, VulkanObjectType object_type, const uint64_t &target,
269906727c7f56d1080aff506a9ae1ae9d8c174b3e9dMark Lobodzinski                            float lineWidth) {
27003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
2701a27508babf63d50aea75883a3702979193c23683Mark Young
2702a27508babf63d50aea75883a3702979193c23683Mark Young    // First check to see if the physical device supports wide lines.
270351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if ((VK_FALSE == dev_data->enabled_features.wideLines) && (1.0f != lineWidth)) {
27043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object_type], target, __LINE__,
27053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        dsError, "DS",
27063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Attempt to set lineWidth to %f but physical device wideLines feature "
27073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "not supported/enabled so lineWidth must be 1.0f!",
27083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        lineWidth);
2709a27508babf63d50aea75883a3702979193c23683Mark Young    } else {
2710a27508babf63d50aea75883a3702979193c23683Mark Young        // Otherwise, make sure the width falls in the valid range.
271151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if ((dev_data->phys_dev_properties.properties.limits.lineWidthRange[0] > lineWidth) ||
271251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            (dev_data->phys_dev_properties.properties.limits.lineWidthRange[1] < lineWidth)) {
27133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object_type], target,
27143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, dsError, "DS",
27153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Attempt to set lineWidth to %f but physical device limits line width "
27163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "to between [%f, %f]!",
27173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            lineWidth, dev_data->phys_dev_properties.properties.limits.lineWidthRange[0],
27183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            dev_data->phys_dev_properties.properties.limits.lineWidthRange[1]);
2719a27508babf63d50aea75883a3702979193c23683Mark Young        }
2720a27508babf63d50aea75883a3702979193c23683Mark Young    }
2721a27508babf63d50aea75883a3702979193c23683Mark Young
27223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
2723a27508babf63d50aea75883a3702979193c23683Mark Young}
2724a27508babf63d50aea75883a3702979193c23683Mark Young
27255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify that create state for a pipeline is valid
272651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verifyPipelineCreateState(layer_data *dev_data, std::vector<PIPELINE_STATE *> pPipelines, int pipelineIndex) {
27273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
27285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27294c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipeline = pPipelines[pipelineIndex];
27305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If create derivative bit is set, check that we've specified a base
27325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // pipeline correctly, and that the base pipeline was created to allow
27335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // derivatives.
27345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
27354c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pBasePipeline = nullptr;
27365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^
27375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis              (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) {
2738315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // This check is a superset of VALIDATION_ERROR_096005a8 and VALIDATION_ERROR_096005aa
27393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
27409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
27419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified");
27425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) {
27435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) {
27443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
2745df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2746315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_208005a0, "DS",
2747f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline. %s",
2748315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_208005a0]);
27495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
27505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex];
27515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
27525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
275351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            pBasePipeline = getPipelineState(dev_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
27545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
27555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
27573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
27589b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
27599b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives.");
27605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
27615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
2764fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const safe_VkPipelineColorBlendStateCreateInfo *color_blend_state = pPipeline->graphicsPipelineCI.pColorBlendState;
27659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto const render_pass_info = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass)->createInfo.ptr();
2766fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pPipeline->graphicsPipelineCI.subpass];
2767fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        if (color_blend_state->attachmentCount != subpass_desc->colorAttachmentCount) {
27683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(
276951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2770315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005d4, "DS",
2771fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                "vkCreateGraphicsPipelines(): Render pass (0x%" PRIxLEAST64
2772fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                ") subpass %u has colorAttachmentCount of %u which doesn't match the pColorBlendState->attachmentCount of %u. %s",
27739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(pPipeline->graphicsPipelineCI.renderPass), pPipeline->graphicsPipelineCI.subpass,
2774fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                subpass_desc->colorAttachmentCount, color_blend_state->attachmentCount,
2775315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                validation_error_map[VALIDATION_ERROR_096005d4]);
2776fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        }
277751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.independentBlend) {
27783d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (pPipeline->attachments.size() > 1) {
277926c548826ff0f83d12c769b51e7d6f76d1265c0eChris Forbes                VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0];
2780c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
278106811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // Quoting the spec: "If [the independent blend] feature is not enabled, the VkPipelineColorBlendAttachmentState
278206811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // settings for all color attachments must be identical." VkPipelineColorBlendAttachmentState contains
278306811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // only attachment state, so memcmp is best suited for the comparison
278406811df0256552cd7da9d7297672af377463fc4aMark Mueller                    if (memcmp(static_cast<const void *>(pAttachments), static_cast<const void *>(&pAttachments[i]),
278506811df0256552cd7da9d7297672af377463fc4aMark Mueller                               sizeof(pAttachments[0]))) {
27863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        skip |=
2787df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2788315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_0f4004ba, "DS",
2789df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "Invalid Pipeline CreateInfo: If independent blend feature not "
2790df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "enabled, all elements of pAttachments must be identical. %s",
2791315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_0f4004ba]);
279206811df0256552cd7da9d7297672af377463fc4aMark Mueller                        break;
2793c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                    }
27945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
27955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
27965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
279751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.logicOp && (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) {
27983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
2799df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2800315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_0f4004bc, "DS",
2801f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE. %s",
2802315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_0f4004bc]);
28035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
28045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2806a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis    // Ensure the subpass index is valid. If not, then validate_and_capture_pipeline_shader_state
28075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // produces nonsense errors that confuse users. Other layers should already
28085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // emit errors for renderpass being invalid.
28099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto renderPass = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass);
2810fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    if (renderPass && pPipeline->graphicsPipelineCI.subpass >= renderPass->createInfo.subpassCount) {
28113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2812315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005ee, "DS",
28133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: Subpass index %u "
28143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "is out of range for this renderpass (0..%u). %s",
28153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pPipeline->graphicsPipelineCI.subpass, renderPass->createInfo.subpassCount - 1,
2816315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005ee]);
28175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
281959ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis    if (validate_and_capture_pipeline_shader_state(dev_data, pPipeline)) {
28203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = true;
28215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
282252156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    // Each shader's stage must be unique
282352156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    if (pPipeline->duplicate_shaders) {
282452156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        for (uint32_t stage = VK_SHADER_STAGE_VERTEX_BIT; stage & VK_SHADER_STAGE_ALL_GRAPHICS; stage <<= 1) {
282552156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            if (pPipeline->duplicate_shaders & stage) {
28269b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
28279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
28289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Invalid Pipeline CreateInfo State: Multiple shaders provided for stage %s",
28299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                string_VkShaderStageFlagBits(VkShaderStageFlagBits(stage)));
283052156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            }
283152156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        }
283252156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    }
28335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VS is required
28345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
2835315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2836315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005ae, "DS",
2837315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "Invalid Pipeline CreateInfo State: Vertex Shader required. %s",
2838315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005ae]);
28395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Either both or neither TC/TE shaders should be defined
28413067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    bool has_control = (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0;
28423067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    bool has_eval = (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0;
28433067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    if (has_control && !has_eval) {
28443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2845315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005b2, "DS",
28463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
2847315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005b2]);
2848f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
28493067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    if (!has_control && has_eval) {
28503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2851315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005b4, "DS",
28523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
2853315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005b4]);
28545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Compute shaders should be specified independent of Gfx shaders
2856f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) {
28573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2858315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005b0, "DS",
28593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline. %s",
2860315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005b0]);
28615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
28635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Mismatching primitive topology and tessellation fails graphics pipeline creation.
28643067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    if (has_control && has_eval &&
2865ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        (!pPipeline->graphicsPipelineCI.pInputAssemblyState ||
2866ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         pPipeline->graphicsPipelineCI.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
28673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2868315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005c0, "DS",
28693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: "
28703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
28713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "topology for tessellation pipelines. %s",
2872315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005c0]);
28735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2874ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pInputAssemblyState &&
2875ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        pPipeline->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
28763067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton        if (!has_control || !has_eval) {
28773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2878315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005c2, "DS",
28793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Invalid Pipeline CreateInfo State: "
28803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
28813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "topology is only valid for tessellation pipelines. %s",
2882315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_096005c2]);
28835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
28845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2885f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
28866b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen    // If a rasterization state is provided...
2887a27508babf63d50aea75883a3702979193c23683Mark Young    if (pPipeline->graphicsPipelineCI.pRasterizationState) {
28886b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // Make sure that the line width conforms to the HW.
2889a27508babf63d50aea75883a3702979193c23683Mark Young        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_LINE_WIDTH)) {
28909b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip |=
28919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                verifyLineWidth(dev_data, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, kVulkanObjectTypePipeline,
28929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), pPipeline->graphicsPipelineCI.pRasterizationState->lineWidth);
2893a27508babf63d50aea75883a3702979193c23683Mark Young        }
28945dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes
289558c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski        if ((pPipeline->graphicsPipelineCI.pRasterizationState->depthClampEnable == VK_TRUE) &&
289658c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski            (!dev_data->enabled_features.depthClamp)) {
28973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2898315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_1020061c, "DS",
28993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCreateGraphicsPipelines(): the depthClamp device feature is disabled: the depthClampEnable "
29003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "member of the VkPipelineRasterizationStateCreateInfo structure must be set to VK_FALSE. %s",
2901315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1020061c]);
290258c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski        }
290358c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski
2904434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_BIAS) &&
2905434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            (pPipeline->graphicsPipelineCI.pRasterizationState->depthBiasClamp != 0.0) &&
2906434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            (!dev_data->enabled_features.depthBiasClamp)) {
29073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
29089b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
29093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCreateGraphicsPipelines(): the depthBiasClamp device feature is disabled: the depthBiasClamp "
29103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "member of the VkPipelineRasterizationStateCreateInfo structure must be set to 0.0 unless the "
29113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "VK_DYNAMIC_STATE_DEPTH_BIAS dynamic state is enabled");
2912434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
2913434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski
29146b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // If rasterization is enabled...
29156b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        if (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE) {
29166b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            auto subpass_desc = renderPass ? &renderPass->createInfo.pSubpasses[pPipeline->graphicsPipelineCI.subpass] : nullptr;
29176b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
2918148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski            if ((pPipeline->graphicsPipelineCI.pMultisampleState->alphaToOneEnable == VK_TRUE) &&
2919148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski                (!dev_data->enabled_features.alphaToOne)) {
29203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2921315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_10000622, "DS",
29223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "vkCreateGraphicsPipelines(): the alphaToOne device feature is disabled: the alphaToOneEnable "
29233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "member of the VkPipelineMultisampleStateCreateInfo structure must be set to VK_FALSE. %s",
2924315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_10000622]);
2925148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski            }
2926148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski
29276b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            // If subpass uses a depth/stencil attachment, pDepthStencilState must be a pointer to a valid structure
29286b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            if (subpass_desc && subpass_desc->pDepthStencilAttachment &&
29296b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
29306b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                if (!pPipeline->graphicsPipelineCI.pDepthStencilState) {
29313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2932315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005e0, "DS",
29333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Invalid Pipeline CreateInfo State: pDepthStencilState is NULL when rasterization is "
29343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "enabled and subpass uses a depth/stencil attachment. %s",
2935315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_096005e0]);
29369580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski
29379580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                } else if ((pPipeline->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE) &&
29389580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                           (!dev_data->enabled_features.depthBounds)) {
29393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
2940df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
29419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
29429580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                        "vkCreateGraphicsPipelines(): the depthBounds device feature is disabled: the depthBoundsTestEnable "
29439580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                        "member of the VkPipelineDepthStencilStateCreateInfo structure must be set to VK_FALSE.");
29446b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                }
29455dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes            }
2946326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen
2947326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            // If subpass uses color attachments, pColorBlendState must be valid pointer
2948326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            if (subpass_desc) {
2949326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                uint32_t color_attachment_count = 0;
2950326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; ++i) {
2951326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    if (subpass_desc->pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
2952326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                        ++color_attachment_count;
2953326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    }
2954326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
2955326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                if (color_attachment_count > 0 && pPipeline->graphicsPipelineCI.pColorBlendState == nullptr) {
29563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2957315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005e2, "DS",
29583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Invalid Pipeline CreateInfo State: pColorBlendState is NULL when rasterization is "
29593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "enabled and subpass uses color attachments. %s",
2960315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_096005e2]);
2961326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
2962326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            }
29635dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes        }
29645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
29656b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
29663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
29675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
29685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
29695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free the Pipeline nodes
297051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePipelines(layer_data *dev_data) {
297151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->pipelineMap.size() <= 0) return;
297251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto &pipe_map_pair : dev_data->pipelineMap) {
2973ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        delete pipe_map_pair.second;
29745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
297551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->pipelineMap.clear();
29765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
29775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
29785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Block of code at start here specifically for managing/tracking DSs
29795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
29805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Pool node ptr for specified pool or else NULL
29819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDESCRIPTOR_POOL_STATE *GetDescriptorPoolState(const layer_data *dev_data, const VkDescriptorPool pool) {
2982bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    auto pool_it = dev_data->descriptorPoolMap.find(pool);
2983bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    if (pool_it == dev_data->descriptorPoolMap.end()) {
29845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
29855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2986bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    return pool_it->second;
29875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
29885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
29895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
29905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// func_str is the name of the calling function
2991e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return false if no errors occur
2992e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
29930dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlisstatic bool validateIdleDescriptorSet(const layer_data *dev_data, VkDescriptorSet set, std::string func_str) {
2994cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.idle_descriptor_set) return false;
29953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
29960dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    auto set_node = dev_data->setMap.find(set);
29970dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    if (set_node == dev_data->setMap.end()) {
29983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
29999b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
30003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.", func_str.c_str(),
30019b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(set));
30025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
30031c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis        // TODO : This covers various error cases so should pass error enum into this function and use passed in enum here
30045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (set_node->second->in_use.load()) {
30053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
3006315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(set), __LINE__, VALIDATION_ERROR_2860026a, "DS",
30073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that is in use by a command buffer. %s",
3008315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            func_str.c_str(), HandleToUint64(set), validation_error_map[VALIDATION_ERROR_2860026a]);
30095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
30105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
30113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
30125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
3013f80bf38f4fb3f177b3e1be11b7b1c5edcdbf7d9bChris Forbes
3014e6651096ed8f07840447783c66827cc16d659a49Tobin Ehlis// Remove set from setMap and delete the set
30159dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlisstatic void freeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
30169dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    dev_data->setMap.erase(descriptor_set->GetSet());
30179dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    delete descriptor_set;
30189dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis}
30195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all DS Pools including their Sets & related sub-structs
30205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
302151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePools(layer_data *dev_data) {
302251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->descriptorPoolMap.size() <= 0) return;
302351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto ii = dev_data->descriptorPoolMap.begin(); ii != dev_data->descriptorPoolMap.end(); ++ii) {
3024c5f47f0a54e14c47d402aeabc6498d981ecda9ccTobin Ehlis        // Remove this pools' sets from setMap and delete them
3025cb9ce9e05b8e939d3da35c64997c70049877f4feTobin Ehlis        for (auto ds : (*ii).second->sets) {
302651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            freeDescriptorSet(dev_data, ds);
30275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
3028f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis        (*ii).second->sets.clear();
30295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
303051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->descriptorPoolMap.clear();
30315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
303351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void clearDescriptorPool(layer_data *dev_data, const VkDevice device, const VkDescriptorPool pool,
30345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                VkDescriptorPoolResetFlags flags) {
30359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pPool = GetDescriptorPoolState(dev_data, pool);
3036de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // TODO: validate flags
3037de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // For every set off of this pool, clear it, remove from setMap, and free cvdescriptorset::DescriptorSet
3038de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (auto ds : pPool->sets) {
303951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        freeDescriptorSet(dev_data, ds);
3040de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    }
3041de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->sets.clear();
3042de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // Reset available count for each type and available sets for this pool
3043de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
3044de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis        pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
30455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3046de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->availableSets = pPool->maxSets;
30475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For given CB object, fetch associated CB Node from map
30509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *dev_data, const VkCommandBuffer cb) {
305151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->commandBufferMap.find(cb);
305251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->commandBufferMap.end()) {
30535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
30545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
30555121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbes    return it->second;
30565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
305829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis// If a renderpass is active, verify that the given command type is appropriate for current subpass state
305929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlisbool ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
3060cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pCB->activeRenderPass) return false;
30613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3062d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis    if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS &&
3063d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis        (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS)) {
30643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
30659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
30663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Commands cannot be called in a subpass using secondary command buffers.");
30675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) {
30683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
30699b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
30703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdExecuteCommands() cannot be called in a subpass using inline commands.");
30715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
30723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
30735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3075baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardtbool ValidateCmdQueueFlags(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const char *caller_name, VkQueueFlags required_flags,
3076baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           UNIQUE_VALIDATION_ERROR_CODE error_code) {
3077baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    auto pool = GetCommandPoolNode(dev_data, cb_node->createInfo.commandPool);
3078baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    if (pool) {
3079baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        VkQueueFlags queue_flags = dev_data->phys_dev_properties.queue_family_properties[pool->queueFamilyIndex].queueFlags;
3080baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        if (!(required_flags & queue_flags)) {
3081baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            string required_flags_string;
3082baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            for (auto flag : {VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT}) {
3083baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                if (flag & required_flags) {
3084baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    if (required_flags_string.size()) {
3085baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                        required_flags_string += " or ";
3086baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    }
3087baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    required_flags_string += string_VkQueueFlagBits(flag);
3088baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                }
3089baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            }
3090baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
30919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(cb_node->commandBuffer), __LINE__, error_code, "DS",
3092baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           "Cannot call %s on a command buffer allocated from a pool without %s capabilities. %s.", caller_name,
3093baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           required_flags_string.c_str(), validation_error_map[error_code]);
3094baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        }
3095baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    }
30965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
30975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3099d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbesstatic char const * GetCauseStr(VK_OBJECT obj) {
3100d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes    if (obj.type == kVulkanObjectTypeDescriptorSet)
3101d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes        return "destroyed or updated";
3102d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes    if (obj.type == kVulkanObjectTypeCommandBuffer)
3103d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes        return "destroyed or rerecorded";
3104d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes    return "destroyed";
3105d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes}
3106d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes
3107ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinskistatic bool ReportInvalidCommandBuffer(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source) {
3108ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    bool skip = false;
3109ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    for (auto obj : cb_state->broken_bindings) {
31107a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        const char *type_str = object_string[obj.type];
3111d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes        const char *cause_str = GetCauseStr(obj);
3112ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
31139b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(cb_state->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
3114ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        "You are adding %s to command buffer 0x%p that is invalid because bound %s 0x%" PRIxLEAST64 " was %s.",
3115ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        call_source, cb_state->commandBuffer, type_str, obj.handle, cause_str);
3116ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    }
3117ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    return skip;
3118ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski}
3119ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
3120623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Validate the given command being added to the specified cmd buffer, flagging errors if CB is not in the recording state or if
3121623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// there's an issue with the Cmd ordering
3122946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskibool ValidateCmd(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd, const char *caller_name) {
312333f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes    switch (cb_state->state) {
312433f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        case CB_RECORDING:
312533f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return ValidateCmdSubpassState(dev_data, cb_state, cmd);
312633f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes
312733f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        case CB_INVALID:
312833f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return ReportInvalidCommandBuffer(dev_data, cb_state, caller_name);
312933f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes
313033f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        default:
313133f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
31329b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS",
313333f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes                           "You must call vkBeginCommandBuffer() before this call to %s", caller_name);
31345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
313629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis
31371ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlisvoid UpdateCmdBufferLastCmd(GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd) {
313829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    if (cb_state->state == CB_RECORDING) {
313929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        cb_state->last_cmd = cmd;
314029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    }
314129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis}
31427e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For given object struct return a ptr of BASE_NODE type for its wrapping struct
31437e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin EhlisBASE_NODE *GetStateStructPtrFromObject(layer_data *dev_data, VK_OBJECT object_struct) {
31447e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_ptr = nullptr;
31457e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    switch (object_struct.type) {
3146ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDescriptorSet: {
31479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(object_struct.handle));
3148cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3149cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3150ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeSampler: {
31519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSamplerState(dev_data, reinterpret_cast<VkSampler &>(object_struct.handle));
3152cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3153cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3154ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeQueryPool: {
31559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(object_struct.handle));
3156cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3157cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3158ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypePipeline: {
3159cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getPipelineState(dev_data, reinterpret_cast<VkPipeline &>(object_struct.handle));
3160cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3161cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3162ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeBuffer: {
31639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object_struct.handle));
3164cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3165cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3166ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeBufferView: {
31679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(object_struct.handle));
3168cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3170ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeImage: {
31719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageState(dev_data, reinterpret_cast<VkImage &>(object_struct.handle));
3172cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3173cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3174ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeImageView: {
31759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageViewState(dev_data, reinterpret_cast<VkImageView &>(object_struct.handle));
3176cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3178ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeEvent: {
31799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetEventNode(dev_data, reinterpret_cast<VkEvent &>(object_struct.handle));
3180cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3181cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3182ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDescriptorPool: {
31839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(object_struct.handle));
3184cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3185cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3186ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeCommandPool: {
31879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(object_struct.handle));
3188cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3189cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3190ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeFramebuffer: {
31919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(object_struct.handle));
3192cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3194ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeRenderPass: {
31959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(object_struct.handle));
3196cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3198ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDeviceMemory: {
31999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(object_struct.handle));
3200cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3201cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3202cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
3203cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO : Any other objects to be handled here?
3204cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            assert(0);
3205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3206bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis    }
32077e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    return base_ptr;
32087e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
32097e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis
32107e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// Tie the VK_OBJECT to the cmd buffer which includes:
32117e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add object_binding to cmd buffer
32127e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add cb_binding to object
32137e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void addCommandBufferBinding(std::unordered_set<GLOBAL_CB_NODE *> *cb_bindings, VK_OBJECT obj, GLOBAL_CB_NODE *cb_node) {
32147e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_bindings->insert(cb_node);
32157e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_node->object_bindings.insert(obj);
32167e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
32177e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For a given object, if cb_node is in that objects cb_bindings, remove cb_node
32187e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void removeCommandBufferBinding(layer_data *dev_data, VK_OBJECT const *object, GLOBAL_CB_NODE *cb_node) {
32197e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_obj = GetStateStructPtrFromObject(dev_data, *object);
3220cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (base_obj) base_obj->cb_bindings.erase(cb_node);
3221bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis}
32225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Reset the command buffer state
32235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Maintain the createInfo and set state to CB_NEW, but clear all other state
3224400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlisstatic void resetCB(layer_data *dev_data, const VkCommandBuffer cb) {
3225400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis    GLOBAL_CB_NODE *pCB = dev_data->commandBufferMap[cb];
32265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
3227b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        pCB->in_use.store(0);
3228347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        pCB->last_cmd = CMD_NONE;
32295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Reset CB state (note that createInfo is not cleared)
32305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->commandBuffer = cb;
32315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
32325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
3233b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes        pCB->hasDrawCmd = false;
32345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->state = CB_NEW;
32355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->submitCount = 0;
32365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status = 0;
3237b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->viewportMask = 0;
3238b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->scissorMask = 0;
323993c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
324072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
324172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            pCB->lastBound[i].reset();
324272d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        }
324393c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
32445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo));
3245ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        pCB->activeRenderPass = nullptr;
32465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE;
32475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpass = 0;
3248e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        pCB->broken_bindings.clear();
32495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEvents.clear();
32505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.clear();
3251c7e6bc41aa9c6e5a677b138b9459b252cd3bedf2Mark Lobodzinski        pCB->writeEventsBeforeWait.clear();
32525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEventsBeforeQueryReset.clear();
32535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->queryToStateMap.clear();
32545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.clear();
32555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->startedQueries.clear();
32565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->imageLayoutMap.clear();
32575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->eventToStageMap.clear();
32585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->drawData.clear();
32595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.clear();
326058b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        pCB->vertex_buffer_used = false;
32615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->primaryCommandBuffer = VK_NULL_HANDLE;
32621a3660584634742a3297915c94768d73f360e794Chris Forbes        // If secondary, invalidate any primary command buffer that may call us.
32631a3660584634742a3297915c94768d73f360e794Chris Forbes        if (pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {
32641a3660584634742a3297915c94768d73f360e794Chris Forbes            invalidateCommandBuffers(dev_data,
32651a3660584634742a3297915c94768d73f360e794Chris Forbes                                     pCB->linkedCommandBuffers,
32661a3660584634742a3297915c94768d73f360e794Chris Forbes                                     {HandleToUint64(cb), kVulkanObjectTypeCommandBuffer});
32671a3660584634742a3297915c94768d73f360e794Chris Forbes        }
32681a3660584634742a3297915c94768d73f360e794Chris Forbes
32691a3660584634742a3297915c94768d73f360e794Chris Forbes        // Remove reverse command buffer links.
32701a3660584634742a3297915c94768d73f360e794Chris Forbes        for (auto pSubCB : pCB->linkedCommandBuffers) {
32711a3660584634742a3297915c94768d73f360e794Chris Forbes            pSubCB->linkedCommandBuffers.erase(pCB);
32721a3660584634742a3297915c94768d73f360e794Chris Forbes        }
32731a3660584634742a3297915c94768d73f360e794Chris Forbes        pCB->linkedCommandBuffers.clear();
32747a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateImages.clear();
32757a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateBuffers.clear();
3276400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, pCB);
3277b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.clear();
3278d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.clear();
327993c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
3280bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        // Remove object bindings
3281bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        for (auto obj : pCB->object_bindings) {
3282bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis            removeCommandBufferBinding(dev_data, &obj, pCB);
3283bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        }
3284a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        pCB->object_bindings.clear();
328593c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        // Remove this cmdBuffer's reference from each FrameBuffer's CB ref list
328693c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        for (auto framebuffer : pCB->framebuffers) {
32879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
3288cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(pCB);
328993c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        }
329093c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        pCB->framebuffers.clear();
32917003b38da5cc27a063af3c45080f3a35438283eeTobin Ehlis        pCB->activeFramebuffer = VK_NULL_HANDLE;
32925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
32935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Set PSO-related status bits for CB, including dynamic state set via PSO
32964c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe) {
32975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Account for any dynamic state not set via this PSO
3298ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (!pPipe->graphicsPipelineCI.pDynamicState ||
3299cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        !pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount) {  // All state is static
33004052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        pCB->status |= CBSTATUS_ALL_STATE_SET;
33015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
33025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // First consider all state on
33035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Then unset any state that's noted as dynamic in PSO
33045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Finally OR that into CB statemask
33054052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        CBStatusFlags psoDynStateMask = CBSTATUS_ALL_STATE_SET;
3306ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        for (uint32_t i = 0; i < pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
3307ca546210846c65808717f8875deae39bd227c240Tobin Ehlis            switch (pPipe->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) {
3308cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_LINE_WIDTH:
3309cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET;
3310cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3311cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BIAS:
3312cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET;
3313cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3314cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
3315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_BLEND_CONSTANTS_SET;
3316cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3317cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
3318cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET;
3319cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3320cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
3321cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET;
3322cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3323cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
3324cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET;
3325cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3326cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
3327cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET;
3328cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3329cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
3330cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // TODO : Flag error here
3331cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
33325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
33335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
33345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= psoDynStateMask;
33355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3338623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Flags validation error if the associated call is made inside a render pass. The apiName routine should ONLY be called outside a
3339623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// render pass.
334051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool insideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3341e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool inside = false;
33425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass) {
334351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        inside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
33449b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                         HandleToUint64(pCB->commandBuffer), __LINE__, msgCode, "DS",
3345ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         "%s: It is invalid to issue this call inside an active render pass (0x%" PRIxLEAST64 "). %s", apiName,
33469b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                         HandleToUint64(pCB->activeRenderPass->renderPass), validation_error_map[msgCode]);
33475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return inside;
33495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Flags validation error if the associated call is made outside a render pass. The apiName
33525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// routine should ONLY be called inside a render pass.
335351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool outsideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3354e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool outside = false;
33555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
33565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
33575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
335851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        outside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
33599b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                          HandleToUint64(pCB->commandBuffer), __LINE__, msgCode, "DS",
3360ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          "%s: This call must be issued inside an active render pass. %s", apiName, validation_error_map[msgCode]);
33615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return outside;
33635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3365f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic void init_core_validation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
3366b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
33675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33697a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis// For the given ValidationCheck enum, set all relevant instance disabled flags to true
33707a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlisvoid SetDisabledFlags(instance_layer_data *instance_data, VkValidationFlagsEXT *val_flags_struct) {
33717a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    for (uint32_t i = 0; i < val_flags_struct->disabledValidationCheckCount; ++i) {
33727a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        switch (val_flags_struct->pDisabledValidationChecks[i]) {
337359ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis            case VK_VALIDATION_CHECK_SHADERS_EXT:
337459ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis                instance_data->disabled.shader_validation = true;
337559ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis                break;
33767a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            case VK_VALIDATION_CHECK_ALL_EXT:
33777a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                // Set all disabled flags to true
33787a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                instance_data->disabled.SetAll(true);
33797a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                break;
33807a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            default:
33817a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                break;
33827a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        }
33837a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    }
33847a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis}
33857a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis
3386bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
3387bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkInstance *pInstance) {
33885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
33895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
33915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
33925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
3393cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
33945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
33965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
33975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
3399cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (result != VK_SUCCESS) return result;
34005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
340156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
340256a5ba3e60a723781945959ffc10e2e215350de5Chia-I Wu    instance_data->instance = *pInstance;
34039172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
34049172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->report_data = debug_report_create_instance(
34059172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
34060cf009a4e2a5c22e4645f343c7a998f188a22015Chris Forbes    instance_data->extensions.InitFromInstanceCreateInfo(pCreateInfo);
3407b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    init_core_validation(instance_data, pAllocator);
3408825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski
34095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
34107a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    // Parse any pNext chains
34117a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    if (pCreateInfo->pNext) {
34127a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        GENERIC_HEADER *struct_header = (GENERIC_HEADER *)pCreateInfo->pNext;
34137a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        while (struct_header) {
34147a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            // Check for VkValidationFlagsExt
34157a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            if (VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT == struct_header->sType) {
34167a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                SetDisabledFlags(instance_data, (VkValidationFlagsEXT *)struct_header);
34177a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            }
34187a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            struct_header = (GENERIC_HEADER *)struct_header->pNext;
34197a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        }
34207a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    }
34215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
34235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
342525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Hook DestroyInstance to remove tableInstanceMap entry
342689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
34275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
34285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(instance);
34295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TBD: Need any locking this early, in case this function is called at the
34305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // same time by more than one thread?
343156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
34329172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
34335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3434b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
34355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Clean up logging callback, if any
34369172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    while (instance_data->logging_callback.size() > 0) {
34379172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
34389172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
34399172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        instance_data->logging_callback.pop_back();
34405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34429172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_debug_report_destroy_instance(instance_data->report_data);
34435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data_map.erase(key);
34445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34465770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstatic bool ValidatePhysicalDeviceQueueFamily(instance_layer_data *instance_data, const PHYSICAL_DEVICE_STATE *pd_state,
34475770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                              uint32_t requested_queue_family, int32_t err_code, const char *cmd_name,
34485770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                              const char *queue_family_var_name, const char *vu_note = nullptr) {
34493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
34505770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34515770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (!vu_note) vu_note = validation_error_map[err_code];
34525770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34535770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    const char *conditional_ext_cmd =
3454d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        instance_data->extensions.vk_khr_get_physical_device_properties_2 ? "or vkGetPhysicalDeviceQueueFamilyProperties2KHR" : "";
34555770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34565770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::string count_note = (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState)
34575770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                 ? "the pQueueFamilyPropertyCount was never obtained"
34585770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                 : "i.e. is not less than " + std::to_string(pd_state->queue_family_count);
34595770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34605770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (requested_queue_family >= pd_state->queue_family_count) {
34613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
34629b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pd_state->phys_device), __LINE__, err_code, "DL",
34639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "%s: %s (= %" PRIu32
34649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        ") is not less than any previously obtained pQueueFamilyPropertyCount from "
34655770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                        "vkGetPhysicalDeviceQueueFamilyProperties%s (%s). %s",
34665770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                        cmd_name, queue_family_var_name, requested_queue_family, conditional_ext_cmd, count_note.c_str(), vu_note);
34675770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    }
34685770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return skip;
34695770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus}
34705770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34715770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus// Verify VkDeviceQueueCreateInfos
34725770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstatic bool ValidateDeviceQueueCreateInfos(instance_layer_data *instance_data, const PHYSICAL_DEVICE_STATE *pd_state,
34735770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                           uint32_t info_count, const VkDeviceQueueCreateInfo *infos) {
34745770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    bool skip = false;
34755770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34765770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    for (uint32_t i = 0; i < info_count; ++i) {
34775770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        const auto requested_queue_family = infos[i].queueFamilyIndex;
34785770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34795770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        // Verify that requested queue family is known to be valid at this point in time
34805770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        std::string queue_family_var_name = "pCreateInfo->pQueueCreateInfos[" + std::to_string(i) + "].queueFamilyIndex";
3481315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, requested_queue_family, VALIDATION_ERROR_06c002fa,
34825770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                  "vkCreateDevice", queue_family_var_name.c_str());
34835770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34845770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        // Verify that requested  queue count of queue family is known to be valid at this point in time
34855770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        if (requested_queue_family < pd_state->queue_family_count) {
34865770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            const auto requested_queue_count = infos[i].queueCount;
34875770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            const auto queue_family_props_count = pd_state->queue_family_properties.size();
34885770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            const bool queue_family_has_props = requested_queue_family < queue_family_props_count;
3489d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski            const char *conditional_ext_cmd = instance_data->extensions.vk_khr_get_physical_device_properties_2
34905770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                  ? "or vkGetPhysicalDeviceQueueFamilyProperties2KHR"
34915770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                  : "";
34925770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            std::string count_note =
34935770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                !queue_family_has_props
34945770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                    ? "the pQueueFamilyProperties[" + std::to_string(requested_queue_family) + "] was never obtained"
34955770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                    : "i.e. is not less than or equal to " +
34965770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                          std::to_string(pd_state->queue_family_properties[requested_queue_family].queueCount);
34975770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34985770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            if (!queue_family_has_props ||
34995770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                requested_queue_count > pd_state->queue_family_properties[requested_queue_family].queueCount) {
35003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
35019b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(pd_state->phys_device), __LINE__,
3502315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                VALIDATION_ERROR_06c002fc, "DL",
35039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkCreateDevice: pCreateInfo->pQueueCreateInfos[%" PRIu32 "].queueCount (=%" PRIu32
35049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                ") is not "
35055770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                "less than or equal to available queue count for this "
35069b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "pCreateInfo->pQueueCreateInfos[%" PRIu32 "].queueFamilyIndex} (=%" PRIu32
35079b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                ") obtained previously "
35085770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                "from vkGetPhysicalDeviceQueueFamilyProperties%s (%s). %s",
35095770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                i, requested_queue_count, i, requested_queue_family, conditional_ext_cmd, count_note.c_str(),
3510315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_06c002fc]);
3511838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            }
3512838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        }
3513838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    }
35145770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
35153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
3516838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski}
3517838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski
3518f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski// Verify that features have been queried and that they are available
35195770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstatic bool ValidateRequestedFeatures(instance_layer_data *instance_data, const PHYSICAL_DEVICE_STATE *pd_state,
3520bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                      const VkPhysicalDeviceFeatures *requested_features) {
35213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3522f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
35235770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    const VkBool32 *actual = reinterpret_cast<const VkBool32 *>(&pd_state->features);
3524825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski    const VkBool32 *requested = reinterpret_cast<const VkBool32 *>(requested_features);
3525f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // TODO : This is a nice, compact way to loop through struct, but a bad way to report issues
3526f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  Need to provide the struct member name with the issue. To do that seems like we'll
3527f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  have to loop through each struct member which should be done w/ codegen to keep in synch.
3528f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t errors = 0;
3529f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t total_bools = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
3530f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    for (uint32_t i = 0; i < total_bools; i++) {
3531f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        if (requested[i] > actual[i]) {
3532f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            // TODO: Add index to struct member name helper to be able to include a feature name
35335770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
35345770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
35353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "While calling vkCreateDevice(), requesting feature #%u in VkPhysicalDeviceFeatures struct, "
35363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "which is not available on this device.",
35373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            i);
3538f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            errors++;
3539f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        }
3540f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
35415770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (errors && (UNCALLED == pd_state->vkGetPhysicalDeviceFeaturesState)) {
3542f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // If user didn't request features, notify them that they should
3543f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // TODO: Verify this against the spec. I believe this is an invalid use of the API and should return an error
35445770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
35455770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                        0, __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
35463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "You requested features that are unavailable on this device. You should first query feature "
35473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "availability by calling vkGetPhysicalDeviceFeatures().");
3548f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
35493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
3550f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
3551f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
355289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
355389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
35543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
35555770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
3556f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
35575770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::unique_lock<std::mutex> lock(global_lock);
3558f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    auto pd_state = GetPhysicalDeviceState(instance_data, gpu);
3559f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
3560f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // TODO: object_tracker should perhaps do this instead
3561f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    //       and it does not seem to currently work anyway -- the loader just crashes before this point
3562f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (!GetPhysicalDeviceState(instance_data, gpu)) {
3563f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
3564f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                        0, __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
3565f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                        "Invalid call to vkCreateDevice() w/o first calling vkEnumeratePhysicalDevices().");
3566f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    }
3567f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
3568f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // Check that any requested features are available
3569f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    if (pCreateInfo->pEnabledFeatures) {
35705770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        skip |= ValidateRequestedFeatures(instance_data, pd_state, pCreateInfo->pEnabledFeatures);
3571f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
35725770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    skip |=
35735770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        ValidateDeviceQueueCreateInfos(instance_data, pd_state, pCreateInfo->queueCreateInfoCount, pCreateInfo->pQueueCreateInfos);
3574f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
35755770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
35761d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller
35775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
35785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
35805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
35815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
358256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice");
35835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (fpCreateDevice == NULL) {
35845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_INITIALIZATION_FAILED;
35855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
35865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
35885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
35895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35905770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.unlock();
35915770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
35925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
35935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result != VK_SUCCESS) {
35945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return result;
35955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
35965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35975770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.lock();
359856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
35995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
360056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->instance_data = instance_data;
36015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Setup device dispatch table
360256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
360356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->device = *pDevice;
3604ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    // Save PhysicalDevice handle
360556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->physical_device = gpu;
36065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
360756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->report_data = layer_debug_report_create_device(instance_data->report_data, *pDevice);
3608a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski    device_data->extensions.InitFromDeviceCreateInfo(&instance_data->extensions, pCreateInfo);
3609d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski
36105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Get physical device limits for this device
361156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &(device_data->phys_dev_properties.properties));
36125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t count;
361356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
361456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->phys_dev_properties.queue_family_properties.resize(count);
361556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(
361656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        gpu, &count, &device_data->phys_dev_properties.queue_family_properties[0]);
36175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO: device limits should make sure these are compatible
36185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCreateInfo->pEnabledFeatures) {
361956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        device_data->enabled_features = *pCreateInfo->pEnabledFeatures;
36205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
362156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        memset(&device_data->enabled_features, 0, sizeof(VkPhysicalDeviceFeatures));
36225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3623e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    // Store physical device properties and physical device mem limits into device layer_data structs
362456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceMemoryProperties(gpu, &device_data->phys_dev_mem_props);
362556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &device_data->phys_dev_props);
3626b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
36275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
36295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
36315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// prototype
363489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
36355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
36363ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    bool skip = false;
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());
3651a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    for (auto del_layout : dev_data->descriptorSetLayoutMap) {
3652a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis        delete del_layout.second;
3653a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    }
3654fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis    dev_data->descriptorSetLayoutMap.clear();
36555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageViewMap.clear();
36565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageMap.clear();
36575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageSubresourceMap.clear();
36585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageLayoutMap.clear();
36595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferViewMap.clear();
36605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferMap.clear();
36611344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    // Queues persist until device is destroyed
36621344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    dev_data->queueMap.clear();
36635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Report any memory leaks
36645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_debug_report_destroy_device(device);
3665b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
36665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if DISPATCH_MAP_DEBUG
3668414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller    fprintf(stderr, "Device: 0x%p, key: 0x%p\n", device, key);
36695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
36703ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    if (!skip) {
36714a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyDevice(device, pAllocator);
36723ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis        layer_data_map.erase(key);
36735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
36775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3678208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis// For given stage mask, if Geometry shader stage is on w/o GS being enabled, report geo_error_id
3679208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis//   and if Tessellation Control or Evaluation shader stages are on w/o TS being enabled, report tess_error_id
3680208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlisstatic bool ValidateStageMaskGsTsEnables(layer_data *dev_data, VkPipelineStageFlags stageMask, const char *caller,
3681208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                         UNIQUE_VALIDATION_ERROR_CODE geo_error_id, UNIQUE_VALIDATION_ERROR_CODE tess_error_id) {
3682208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    bool skip = false;
3683208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.geometryShader && (stageMask & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) {
3684208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
3685cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        geo_error_id, "DL",
3686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT bit set when "
3687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "device does not have geometryShader feature enabled. %s",
3688208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[geo_error_id]);
3689208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
3690208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.tessellationShader &&
3691208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        (stageMask & (VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT))) {
3692208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
3693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        tess_error_id, "DL",
3694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT "
3695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "and/or VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT bit(s) set when device "
3696cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "does not have tessellationShader feature enabled. %s",
3697208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[tess_error_id]);
3698208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
3699208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    return skip;
3700208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis}
3701208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis
3702ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes// Loop through bound objects and increment their in_use counts.
3703ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayesstatic void IncrementBoundObjects(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
3704a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
3705a317e7593a0fe227635fc8241908471acb36c952Chris Forbes        auto base_obj = GetStateStructPtrFromObject(dev_data, obj);
3706ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes        if (base_obj) {
370751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            base_obj->in_use.fetch_add(1);
3708162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis        }
3709a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
3710a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
37115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Track which resources are in-flight by atomically incrementing their "in_use" count
371251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void incrementResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
371351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    cb_node->submitCount++;
37149a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    cb_node->in_use.fetch_add(1);
3715a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
3716a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // First Increment for all "generic" objects bound to cmd buffer, followed by special-case objects below
3717ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes    IncrementBoundObjects(dev_data, cb_node);
3718a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
3719a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
3720a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  should then be flagged prior to calling this function
37219a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto drawDataElement : cb_node->drawData) {
37225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto buffer : drawDataElement.buffers) {
37239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto buffer_state = GetBufferState(dev_data, buffer);
372451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (buffer_state) {
37255cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                buffer_state->in_use.fetch_add(1);
37265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
37275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
37285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37299a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto event : cb_node->writeEventsBeforeWait) {
37309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
3731cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (event_state) event_state->write_in_use++;
3732c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
37335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3735b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Note: This function assumes that the global lock is held by the calling thread.
3736b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// For the given queue, verify the queue state up to the given seq number.
3737b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Currently the only check is to make sure that if there are events to be waited on prior to
3738b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis//  a QueryReset, make sure that all such events have been signalled.
3739d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbesstatic bool VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *initial_queue, uint64_t initial_seq) {
3740b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    bool skip = false;
3741d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3742d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    // sequence number we want to validate up to, per queue
3743d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::unordered_map<QUEUE_STATE *, uint64_t> target_seqs { { initial_queue, initial_seq } };
3744d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    // sequence number we've completed validation for, per queue
3745d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::unordered_map<QUEUE_STATE *, uint64_t> done_seqs;
3746d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::vector<QUEUE_STATE *> worklist { initial_queue };
3747d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3748d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    while (worklist.size()) {
3749d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto queue = worklist.back();
3750d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        worklist.pop_back();
3751d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3752d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto target_seq = target_seqs[queue];
3753d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto seq = std::max(done_seqs[queue], queue->seq);
3754d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto sub_it = queue->submissions.begin() + int(seq - queue->seq);  // seq >= queue->seq
3755d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3756d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        for (; seq < target_seq; ++sub_it, ++seq) {
3757d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            for (auto &wait : sub_it->waitSemaphores) {
3758d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_queue = GetQueueState(dev_data, wait.queue);
3759d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3760d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (other_queue == queue)
3761d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    continue;   // semaphores /always/ point backwards, so no point here.
3762d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3763d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_target_seq = std::max(target_seqs[other_queue], wait.seq);
3764d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_done_seq = std::max(done_seqs[other_queue], other_queue->seq);
3765d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3766d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // if this wait is for another queue, and covers new sequence
3767d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // numbers beyond what we've already validated, mark the new
3768d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // target seq and (possibly-re)add the queue to the worklist.
3769d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (other_done_seq < other_target_seq) {
3770d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    target_seqs[other_queue] = other_target_seq;
3771d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    worklist.push_back(other_queue);
3772d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                }
3773d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            }
3774d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3775d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            for (auto cb : sub_it->cbs) {
3776d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto cb_node = GetCBNode(dev_data, cb);
3777d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (cb_node) {
3778d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    for (auto queryEventsPair : cb_node->waitedEventsBeforeQueryReset) {
3779d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                        for (auto event : queryEventsPair.second) {
3780d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                            if (dev_data->eventMap[event].needsSignaled) {
3781d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3782d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS",
3783d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                "Cannot get query results on queryPool 0x%" PRIx64
3784d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                " with index %d which was guarded by unsignaled event 0x%" PRIx64 ".",
37859b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                HandleToUint64(queryEventsPair.first.pool), queryEventsPair.first.index,
37869b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                HandleToUint64(event));
3787d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                            }
3788b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                        }
3789b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    }
3790b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine                }
3791b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine            }
3792b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        }
3793d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3794d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        // finally mark the point we've now validated this queue to.
3795d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        done_seqs[queue] = seq;
379692b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    }
3797d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3798b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return skip;
3799b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis}
3800b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis
3801b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// When the given fence is retired, verify outstanding queue operations through the point of the fence
3802b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic bool VerifyQueueStateToFence(layer_data *dev_data, VkFence fence) {
38039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto fence_state = GetFenceNode(dev_data, fence);
3804b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    if (VK_NULL_HANDLE != fence_state->signaler.first) {
38059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        return VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, fence_state->signaler.first), fence_state->signaler.second);
3806b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    }
3807b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return false;
3808b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
38097d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes
3810a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis// Decrement in-use count for objects bound to command buffer
38112f8cbf3b166e175174877a59929902e005953d6dTobin Ehlisstatic void DecrementBoundResources(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
381200e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis    BASE_NODE *base_obj = nullptr;
3813a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
38147e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis        base_obj = GetStateStructPtrFromObject(dev_data, obj);
381500e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        if (base_obj) {
381600e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis            base_obj->in_use.fetch_sub(1);
381700e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        }
3818a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
3819a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
3820da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes
382136c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void RetireWorkOnQueue(layer_data *dev_data, QUEUE_STATE *pQueue, uint64_t seq) {
38229867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unordered_map<VkQueue, uint64_t> otherQueueSeqs;
38239867daedbf52debc77d6568162ee21e071699b80Chris Forbes
38249867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll this queue forward, one submission at a time.
38259867daedbf52debc77d6568162ee21e071699b80Chris Forbes    while (pQueue->seq < seq) {
3826bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &submission = pQueue->submissions.front();
38279867daedbf52debc77d6568162ee21e071699b80Chris Forbes
3828bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &wait : submission.waitSemaphores) {
38299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, wait.semaphore);
3830c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
3831c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
3832c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
3833bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto &lastSeq = otherQueueSeqs[wait.queue];
38349867daedbf52debc77d6568162ee21e071699b80Chris Forbes            lastSeq = std::max(lastSeq, wait.seq);
3835da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes        }
3836cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
3837bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &semaphore : submission.signalSemaphores) {
38389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
3839c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
3840c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
3841c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
38429867daedbf52debc77d6568162ee21e071699b80Chris Forbes        }
3843cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
38449867daedbf52debc77d6568162ee21e071699b80Chris Forbes        for (auto cb : submission.cbs) {
38459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, cb);
3846c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (!cb_node) {
3847c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                continue;
3848c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
3849a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis            // First perform decrement on general case bound objects
38509a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            DecrementBoundResources(dev_data, cb_node);
38519a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto drawDataElement : cb_node->drawData) {
38529867daedbf52debc77d6568162ee21e071699b80Chris Forbes                for (auto buffer : drawDataElement.buffers) {
38539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto buffer_state = GetBufferState(dev_data, buffer);
38545cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                    if (buffer_state) {
38555cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                        buffer_state->in_use.fetch_sub(1);
38569867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
38579867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
3858da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
38599a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto event : cb_node->writeEventsBeforeWait) {
38609867daedbf52debc77d6568162ee21e071699b80Chris Forbes                auto eventNode = dev_data->eventMap.find(event);
38619867daedbf52debc77d6568162ee21e071699b80Chris Forbes                if (eventNode != dev_data->eventMap.end()) {
38629867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    eventNode->second.write_in_use--;
38639867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
38649867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
38659a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto queryStatePair : cb_node->queryToStateMap) {
38669867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->queryToStateMap[queryStatePair.first] = queryStatePair.second;
38679867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
38689a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto eventStagePair : cb_node->eventToStageMap) {
38699867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second;
3870da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
38710a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine
3872a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            cb_node->in_use.fetch_sub(1);
38730a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
38749867daedbf52debc77d6568162ee21e071699b80Chris Forbes
38759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, submission.fence);
38769867daedbf52debc77d6568162ee21e071699b80Chris Forbes        if (pFence) {
38779867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pFence->state = FENCE_RETIRED;
38780a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
38799867daedbf52debc77d6568162ee21e071699b80Chris Forbes
38809867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->submissions.pop_front();
38819867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->seq++;
3882b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
38839867daedbf52debc77d6568162ee21e071699b80Chris Forbes
38849867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll other queues forward to the highest seq we saw a wait for
38859867daedbf52debc77d6568162ee21e071699b80Chris Forbes    for (auto qs : otherQueueSeqs) {
38869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, qs.first), qs.second);
3887d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
38889867daedbf52debc77d6568162ee21e071699b80Chris Forbes}
3889651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
3890651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// Submit a fence to a queue, delimiting previous fences and previous untracked
3891651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// work by it.
389236c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void SubmitFence(QUEUE_STATE *pQueue, FENCE_NODE *pFence, uint64_t submitCount) {
3893cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes    pFence->state = FENCE_INFLIGHT;
38949867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.first = pQueue->queue;
38959867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.second = pQueue->seq + pQueue->submissions.size() + submitCount;
3896b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
3897b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
389851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
38993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3900a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    if ((pCB->in_use.load() || current_submit_count > 1) &&
39015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
39023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
3903315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        __LINE__, VALIDATION_ERROR_31a0008e, "DS",
39043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Command Buffer 0x%p is already in use and is not marked for simultaneous use. %s", pCB->commandBuffer,
3905315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_31a0008e]);
39065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
39085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3910946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskistatic bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source,
39110de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                                       int current_submit_count, UNIQUE_VALIDATION_ERROR_CODE vu_id) {
3912c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    bool skip = false;
3913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.command_buffer_state) return skip;
39140a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
3915946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if ((cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) &&
3916946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        (cb_state->submitCount + current_submit_count > 1)) {
3917c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
3918c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
3919226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Commandbuffer 0x%p was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT "
3920c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        "set, but has been submitted 0x%" PRIxLEAST64 " times.",
3921946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->commandBuffer, cb_state->submitCount + current_submit_count);
39220a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    }
392394307efee520ad91d5da2ff8f40609b31f05b2efChris Forbes
39245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate that cmd buffers have been updated
3925946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (CB_RECORDED != cb_state->state) {
3926946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (CB_INVALID == cb_state->state) {
3927946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= ReportInvalidCommandBuffer(dev_data, cb_state, call_source);
39280de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski        } else if (CB_NEW == cb_state->state) {
39290de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
39300de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            (uint64_t)(cb_state->commandBuffer), __LINE__, vu_id, "DS",
39310de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "Command buffer 0x%p used in the call to %s is unrecorded and contains no commands. %s",
39320de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            cb_state->commandBuffer, call_source, validation_error_map[vu_id]);
3933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Flag error for using CB w/o vkEndCommandBuffer() called
3934c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
39359b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS",
3936946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "You must call vkEndCommandBuffer() on command buffer 0x%p before this call to %s!",
3937946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            cb_state->commandBuffer, call_source);
39385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
39395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3940c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    return skip;
39415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
394351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
39443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
394551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
394651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
394751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
394851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  should then be flagged prior to calling this function
394951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (auto drawDataElement : cb_node->drawData) {
395051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (auto buffer : drawDataElement.buffers) {
395151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto buffer_state = GetBufferState(dev_data, buffer);
395251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (!buffer_state) {
39533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
39549b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
39559b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Cannot submit cmd buffer using deleted buffer 0x%" PRIx64 ".", HandleToUint64(buffer));
395651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
395751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
395851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
39593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
396051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
396151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
3962f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski// Check that the queue family index of 'queue' matches one of the entries in pQueueFamilyIndices
3963f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinskibool ValidImageBufferQueue(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const VK_OBJECT *object, VkQueue queue, uint32_t count,
3964f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           const uint32_t *indices) {
3965f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    bool found = false;
3966f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    bool skip = false;
3967f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    auto queue_state = GetQueueState(dev_data, queue);
3968f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    if (queue_state) {
3969f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        for (uint32_t i = 0; i < count; i++) {
3970f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            if (indices[i] == queue_state->queueFamilyIndex) {
3971f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                found = true;
3972f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                break;
3973f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            }
3974f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
3975f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
3976f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        if (!found) {
39779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip = log_msg(
39789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object->type], object->handle, __LINE__,
39799b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                DRAWSTATE_INVALID_QUEUE_FAMILY, "DS", "vkQueueSubmit: Command buffer 0x%" PRIxLEAST64 " contains %s 0x%" PRIxLEAST64
39809b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                      " which was not created allowing concurrent access to this queue family %d.",
39819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(cb_node->commandBuffer), object_string[object->type], object->handle, queue_state->queueFamilyIndex);
3982f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
3983f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    }
3984f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    return skip;
3985f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski}
3986f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
39877bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Validate that queueFamilyIndices of primary command buffers match this queue
39887bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Secondary command buffers were previously validated in vkCmdExecuteCommands().
39897bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinskistatic bool validateQueueFamilyIndices(layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkQueue queue) {
39903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
39919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
39929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
39937bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
3994f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    if (pPool && queue_state) {
3995f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        if (pPool->queueFamilyIndex != queue_state->queueFamilyIndex) {
39963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3997315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_31a00094, "DS",
39983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkQueueSubmit: Primary command buffer 0x%p created in queue family %d is being submitted on queue "
39993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "0x%p from queue family %d. %s",
40003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            pCB->commandBuffer, pPool->queueFamilyIndex, queue, queue_state->queueFamilyIndex,
4001315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_31a00094]);
4002f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
4003f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
4004f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        // Ensure that any bound images or buffers created with SHARING_MODE_CONCURRENT have access to the current queue family
4005f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        for (auto object : pCB->object_bindings) {
40067a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            if (object.type == kVulkanObjectTypeImage) {
4007f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(object.handle));
4008f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                if (image_state && image_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
40093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= ValidImageBufferQueue(dev_data, pCB, &object, queue, image_state->createInfo.queueFamilyIndexCount,
40103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                  image_state->createInfo.pQueueFamilyIndices);
4011f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                }
40127a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            } else if (object.type == kVulkanObjectTypeBuffer) {
4013f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object.handle));
4014f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                if (buffer_state && buffer_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
40153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= ValidImageBufferQueue(dev_data, pCB, &object, queue, buffer_state->createInfo.queueFamilyIndexCount,
40163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                  buffer_state->createInfo.pQueueFamilyIndices);
4017f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                }
4018f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            }
4019f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
40207bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
40217bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
40223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
40237bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski}
40247bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
402551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
40265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Track in-use for resources off of primary and any secondary CBs
40273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
4028a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4029a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
4030a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // on device
40313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateCommandBufferSimultaneousUse(dev_data, pCB, current_submit_count);
4032a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
40333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateResources(dev_data, pCB);
4034a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
40351a3660584634742a3297915c94768d73f360e794Chris Forbes    for (auto pSubCB : pCB->linkedCommandBuffers) {
403611decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes        skip |= validateResources(dev_data, pSubCB);
40371a3660584634742a3297915c94768d73f360e794Chris Forbes        // TODO: replace with invalidateCommandBuffers() at recording.
403811decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes        if ((pSubCB->primaryCommandBuffer != pCB->commandBuffer) &&
403911decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes            !(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4040315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4041315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    __LINE__, VALIDATION_ERROR_31a00092, "DS",
4042315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    "Commandbuffer 0x%p was submitted with secondary buffer 0x%p but that buffer has subsequently been bound to "
4043f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "primary cmd buffer 0x%p and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set. %s",
4044315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    pCB->commandBuffer, pSubCB->commandBuffer, pSubCB->primaryCommandBuffer,
4045315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    validation_error_map[VALIDATION_ERROR_31a00092]);
40465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
40475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4048a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4049315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= validateCommandBufferState(dev_data, pCB, "vkQueueSubmit()", current_submit_count, VALIDATION_ERROR_31a00090);
4050a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
40513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
40525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4054bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateFenceForSubmit(layer_data *dev_data, FENCE_NODE *pFence) {
40553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
405681c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4057651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
4058cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_INFLIGHT) {
4059315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // TODO: opportunities for VALIDATION_ERROR_31a00080, VALIDATION_ERROR_316008b4, VALIDATION_ERROR_16400a0e
40603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
40619b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pFence->fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
40629b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Fence 0x%" PRIx64 " is already in use by another submission.", HandleToUint64(pFence->fence));
4063a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
406481c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4065cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        else if (pFence->state == FENCE_RETIRED) {
4066315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // TODO: opportunities for VALIDATION_ERROR_31a0007e, VALIDATION_ERROR_316008b2, VALIDATION_ERROR_16400a0e
40673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
40689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pFence->fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
40693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Fence 0x%" PRIxLEAST64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
40709b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pFence->fence));
4071a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
40725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
407381c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
40743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
407581c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes}
407681c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
407751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void PostCallRecordQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
407851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                      VkFence fence) {
40799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
40809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4081d7d60cccc862fee2d0b3ad410c5fdcc40ddc83aeChris Forbes
4082651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    // Mark the fence in-use.
4083651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
40849867daedbf52debc77d6568162ee21e071699b80Chris Forbes        SubmitFence(pQueue, pFence, std::max(1u, submitCount));
4085651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    }
4086651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
408751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now process each individual submit
40885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
408951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        std::vector<VkCommandBuffer> cbs;
40905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubmitInfo *submit = &pSubmits[submit_idx];
40919867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<SEMAPHORE_WAIT> semaphore_waits;
40929867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<VkSemaphore> semaphore_signals;
40935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
409451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pWaitSemaphores[i];
409551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
409651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
409751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
409851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
409951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    pSemaphore->in_use.fetch_add(1);
410051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
410151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = VK_NULL_HANDLE;
410251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = false;
410351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
410451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
410551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
410651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pSignalSemaphores[i];
410751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
410851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
410951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = queue;
411051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
411151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = true;
411251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->in_use.fetch_add(1);
411351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                semaphore_signals.push_back(semaphore);
411451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
411551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
411651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
411751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
411851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (cb_node) {
411951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                cbs.push_back(submit->pCommandBuffers[i]);
41201a3660584634742a3297915c94768d73f360e794Chris Forbes                for (auto secondaryCmdBuffer : cb_node->linkedCommandBuffers) {
412111decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes                    cbs.push_back(secondaryCmdBuffer->commandBuffer);
412251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
412351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                UpdateCmdBufImageLayouts(dev_data, cb_node);
412451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                incrementResources(dev_data, cb_node);
41251a3660584634742a3297915c94768d73f360e794Chris Forbes                for (auto secondaryCmdBuffer : cb_node->linkedCommandBuffers) {
412611decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes                    incrementResources(dev_data, secondaryCmdBuffer);
412751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
412851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
412951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
413051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(cbs, semaphore_waits, semaphore_signals,
413151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         submit_idx == submitCount - 1 ? fence : VK_NULL_HANDLE);
413251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
413351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
413451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if (pFence && !submitCount) {
413551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // If no submissions, but just dropping a fence on the end of the queue,
413651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // record an empty submission with just the fence, so we can determine
413751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // its completion.
413851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
413951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         fence);
414051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
414151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
414251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
414351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool PreCallValidateQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
414451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                       VkFence fence) {
414551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    auto pFence = GetFenceNode(dev_data, fence);
41463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = ValidateFenceForSubmit(dev_data, pFence);
41473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
414851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        return true;
414951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
415051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
415151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> signaled_semaphores;
415251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> unsignaled_semaphores;
415351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    vector<VkCommandBuffer> current_cmds;
415451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> localImageLayoutMap = dev_data->imageLayoutMap;
415551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now verify each individual submit
415651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
415751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        const VkSubmitInfo *submit = &pSubmits[submit_idx];
415851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
4159315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= ValidateStageMaskGsTsEnables(dev_data, submit->pWaitDstStageMask[i], "vkQueueSubmit()",
4160315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                 VALIDATION_ERROR_13c00098, VALIDATION_ERROR_13c0009a);
416101a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pWaitSemaphores[i];
41629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
416301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
416451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (unsignaled_semaphores.count(semaphore) ||
4165440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                    (!(signaled_semaphores.count(semaphore)) && !(pSemaphore->signaled))) {
41663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
41679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
41683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
41699b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore));
417051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                } else {
417151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.erase(semaphore);
417251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.insert(semaphore);
41731344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
41745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
41755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
41765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
417701a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pSignalSemaphores[i];
41789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
417901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
4180440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                if (signaled_semaphores.count(semaphore) || (!(unsignaled_semaphores.count(semaphore)) && pSemaphore->signaled)) {
41813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
41829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
41833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Queue 0x%p is signaling semaphore 0x%" PRIx64
41843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " that has already been signaled but not waited on by queue 0x%" PRIx64 ".",
41859b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    queue, HandleToUint64(semaphore), HandleToUint64(pSemaphore->signaler.first));
41861344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
418751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.erase(semaphore);
418851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.insert(semaphore);
41891344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
41900a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine            }
41915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
41925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
41939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
4194d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            if (cb_node) {
41953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateCmdBufImageLayouts(dev_data, cb_node, localImageLayoutMap);
419651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                current_cmds.push_back(submit->pCommandBuffers[i]);
41973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= validatePrimaryCommandBufferState(
419851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    dev_data, cb_node, (int)std::count(current_cmds.begin(), current_cmds.end(), submit->pCommandBuffers[i]));
41993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= validateQueueFamilyIndices(dev_data, cb_node, queue);
420051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
4201ea371fa7c8c57edb4d1436e4570cf54f3fc0463fTobin Ehlis                // Potential early exit here as bad object state may crash in delayed function calls
42023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                if (skip) {
420351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    return true;
420451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
420551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
42061344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                // Call submit-time functions to validate/update state
4207d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->validate_functions) {
42083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function();
42091344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4210d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->eventUpdates) {
42113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function(queue);
42121344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4213d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->queryUpdates) {
42143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function(queue);
4215d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
42161344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            }
42175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
42189867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
42193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
422051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
42219867daedbf52debc77d6568162ee21e071699b80Chris Forbes
422251920949f887ce8d3666c73c28ff19a5d8325a37Tony BarbourVKAPI_ATTR VkResult VKAPI_CALL QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
422351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
422451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    std::unique_lock<std::mutex> lock(global_lock);
422551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
422651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip = PreCallValidateQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
4227b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
42285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4229440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
423051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
423151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    VkResult result = dev_data->dispatch_table.QueueSubmit(queue, submitCount, pSubmits, fence);
423251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
423351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.lock();
423451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    PostCallRecordQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
423551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.unlock();
42365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
42375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4239f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic bool PreCallValidateAllocateMemory(layer_data *dev_data) {
4240f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = false;
4241f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (dev_data->memObjMap.size() >= dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount) {
4242f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
4243315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_16c004f8, "MEM",
4244f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        "Number of currently valid memory objects is not less than the maximum allowed (%u). %s",
4245f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount,
4246315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_16c004f8]);
4247f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    }
4248f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return skip;
4249f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4250f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
4251f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic void PostCallRecordAllocateMemory(layer_data *dev_data, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory) {
4252f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    add_mem_obj_info(dev_data, dev_data->device, *pMemory, pAllocateInfo);
4253f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return;
4254f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4255f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
425689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
425789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
4258f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
425956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4260f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    std::unique_lock<std::mutex> lock(global_lock);
4261f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = PreCallValidateAllocateMemory(dev_data);
4262f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (!skip) {
4263f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.unlock();
4264f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        result = dev_data->dispatch_table.AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
4265f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.lock();
4266f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        if (VK_SUCCESS == result) {
4267f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz            PostCallRecordAllocateMemory(dev_data, pAllocateInfo, pMemory);
4268f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        }
4269e12739a56d02ca2fb5f0273862668e7475a21a6cMark Lobodzinski    }
42705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
42715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4273177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis// For given obj node, if it is use, flag a validation error and return callback result, else return false
4274177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisbool ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct,
4275177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                            UNIQUE_VALIDATION_ERROR_CODE error_code) {
4276cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.object_in_use) return false;
4277177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4278177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (obj_node->in_use.load()) {
42797a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip |=
428002a510945ff39f3d9e486e456aca5bfa6ea0c43aMark Lobodzinski            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[obj_struct.type], obj_struct.handle,
42817a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                    __LINE__, error_code, "DS", "Cannot delete %s 0x%" PRIx64 " that is currently in use by a command buffer. %s",
42827a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                    object_string[obj_struct.type], obj_struct.handle, validation_error_map[error_code]);
4283177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4284177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4285177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
42865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4287177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic bool PreCallValidateFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO **mem_info, VK_OBJECT *obj_struct) {
42889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *mem_info = GetMemObjInfo(dev_data, mem);
42899b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(mem), kVulkanObjectTypeDeviceMemory};
4290cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_memory) return false;
4291177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4292177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (*mem_info) {
4293315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *mem_info, *obj_struct, VALIDATION_ERROR_2880054a);
4294177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4295177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4296177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
42975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4298177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic void PostCallRecordFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO *mem_info, VK_OBJECT obj_struct) {
4299177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Clear mem binding for any bound objects
430047705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis    for (auto obj : mem_info->obj_bindings) {
430102a510945ff39f3d9e486e456aca5bfa6ea0c43aMark Lobodzinski        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, get_debug_report_enum[obj.type], obj.handle, __LINE__,
43027a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                MEMTRACK_FREED_MEM_REF, "MEM", "VK Object 0x%" PRIxLEAST64 " still has a reference to mem obj 0x%" PRIxLEAST64,
43039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                obj.handle, HandleToUint64(mem_info->mem));
430447705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        switch (obj.type) {
43057a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            case kVulkanObjectTypeImage: {
43069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
4307cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(image_state);  // Any destroyed images should already be removed from bindings
4308cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                image_state->binding.mem = MEMORY_UNBOUND;
4309cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4310cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
43117a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            case kVulkanObjectTypeBuffer: {
43129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
4313cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(buffer_state);  // Any destroyed buffers should already be removed from bindings
4314cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                buffer_state->binding.mem = MEMORY_UNBOUND;
4315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4316cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4317cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
4318cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Should only have buffer or image objects bound to memory
4319cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(0);
4320177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        }
4321177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4322177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Any bound cmd buffers are now invalid
432339c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, mem_info->cb_bindings, obj_struct);
4324177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    dev_data->memObjMap.erase(mem);
4325177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
4326177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis
4327177063aac84fac6f4e650c2629a08b48be643f96Tobin EhlisVKAPI_ATTR void VKAPI_CALL FreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
432856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4329177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    DEVICE_MEM_INFO *mem_info = nullptr;
4330177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    VK_OBJECT obj_struct;
4331b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4332177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = PreCallValidateFreeMemory(dev_data, mem, &mem_info, &obj_struct);
4333177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (!skip) {
4334177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.unlock();
4335177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        dev_data->dispatch_table.FreeMemory(device, mem, pAllocator);
4336177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.lock();
4337405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (mem != VK_NULL_HANDLE) {
4338405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordFreeMemory(dev_data, mem, mem_info, obj_struct);
4339405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
434074243a735fe102b370237ddf80d3e6f7ec5246dbMark Mueller    }
43415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4343f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis// Validate that given Map memory range is valid. This means that the memory should not already be mapped,
4344f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  and that the size of the map range should be:
4345f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  1. Not zero
4346f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  2. Within the size of the memory allocation
434751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateMapMemRange(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
43483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
43495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (size == 0) {
43513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
43529b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
43533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "VkMapMemory: Attempting to map memory range of size zero");
43545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
435651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto mem_element = dev_data->memObjMap.find(mem);
435751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (mem_element != dev_data->memObjMap.end()) {
435857fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        auto mem_info = mem_element->second.get();
43595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // It is an application error to call VkMapMemory on an object that is already mapped
4360de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (mem_info->mem_range.size != 0) {
43619b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip =
43629b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
43639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
43649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "VkMapMemory: Attempting to map memory on an already-mapped object 0x%" PRIxLEAST64, HandleToUint64(mem));
43655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
43665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate that offset + size is within object's allocationSize
43685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (size == VK_WHOLE_SIZE) {
4369de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if (offset >= mem_info->alloc_info.allocationSize) {
43703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
43719b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                               HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
43723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64
43733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               " with size of VK_WHOLE_SIZE oversteps total array size 0x%" PRIx64,
43743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               offset, mem_info->alloc_info.allocationSize, mem_info->alloc_info.allocationSize);
43755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
43765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
4377de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if ((offset + size) > mem_info->alloc_info.allocationSize) {
43783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4379315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               HandleToUint64(mem), __LINE__, VALIDATION_ERROR_31200552, "MEM",
43803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64 " oversteps total array size 0x%" PRIx64 ". %s",
43813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               offset, size + offset, mem_info->alloc_info.allocationSize,
4382315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               validation_error_map[VALIDATION_ERROR_31200552]);
43835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
43845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
43855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
43875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
438951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void storeMemRanges(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
43909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
439157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4392de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.offset = offset;
4393de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = size;
43945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
439751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool deleteMemRanges(layer_data *dev_data, VkDeviceMemory mem) {
43983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
43999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
440057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4401de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (!mem_info->mem_range.size) {
44025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Valid Usage: memory must currently be mapped
44033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4404315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           HandleToUint64(mem), __LINE__, VALIDATION_ERROR_33600562, "MEM",
44059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           "Unmapping Memory without memory being mapped: mem obj 0x%" PRIxLEAST64 ". %s", HandleToUint64(mem),
4406315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           validation_error_map[VALIDATION_ERROR_33600562]);
44075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4408de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = 0;
44095f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info->shadow_copy) {
44105f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            free(mem_info->shadow_copy_base);
44115f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy_base = 0;
44125f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
44135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
44145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
44153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
44165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
44175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44185f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski// Guard value for pad data
44195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char NoncoherentMemoryFillValue = 0xb;
44205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44215f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinskistatic void initializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
44225f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                     void **ppData) {
44239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
442457fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4425de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->p_driver_data = *ppData;
4426de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        uint32_t index = mem_info->alloc_info.memoryTypeIndex;
4427b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis        if (dev_data->phys_dev_mem_props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
44285f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
44295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
44305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (size == VK_WHOLE_SIZE) {
44315f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                size = mem_info->alloc_info.allocationSize - offset;
44325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
44335f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_pad_size = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
443416769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton            assert(SafeModulo(mem_info->shadow_pad_size,
44355f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment) == 0);
44365f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Ensure start of mapped region reflects hardware alignment constraints
44375f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t map_alignment = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
44385f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
44395f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // From spec: (ppData - offset) must be aligned to at least limits::minMemoryMapAlignment.
44405f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t start_offset = offset % map_alignment;
44415f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Data passed to driver will be wrapped by a guardband of data to detect over- or under-writes.
4442bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            mem_info->shadow_copy_base =
4443bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                malloc(static_cast<size_t>(2 * mem_info->shadow_pad_size + size + map_alignment + start_offset));
44445f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
44455f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy =
44465f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(mem_info->shadow_copy_base) + map_alignment) &
4447bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         ~(map_alignment - 1)) +
4448bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                start_offset;
444916769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton            assert(SafeModulo(reinterpret_cast<uintptr_t>(mem_info->shadow_copy) + mem_info->shadow_pad_size - start_offset,
44505f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  map_alignment) == 0);
44515f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
44526e17c244b21ce43ac57404a00a0d844039eed363Mark Lobodzinski            memset(mem_info->shadow_copy, NoncoherentMemoryFillValue, static_cast<size_t>(2 * mem_info->shadow_pad_size + size));
44535f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            *ppData = static_cast<char *>(mem_info->shadow_copy) + mem_info->shadow_pad_size;
44545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
44555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
44565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
44575f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
4458a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis// Verify that state for fence being waited on is appropriate. That is,
44599867daedbf52debc77d6568162ee21e071699b80Chris Forbes//  a fence being waited on should not already be signaled and
4460a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis//  it should have been submitted on a queue or during acquire next image
446149f6132af865afd5b7f413c91125971ac97c135aChris Forbesstatic inline bool verifyWaitFenceState(layer_data *dev_data, VkFence fence, const char *apiCall) {
44623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
44639b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes
44649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
44659b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes    if (pFence) {
4466cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_UNSIGNALED) {
44673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
44689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
44693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s called for fence 0x%" PRIxLEAST64
44703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " which has not been submitted on a Queue or during "
44713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "acquire next image.",
44729b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            apiCall, HandleToUint64(fence));
44735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
44745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
44753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
44765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4477a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
4478b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void RetireFence(layer_data *dev_data, VkFence fence) {
44799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4480b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes    if (pFence->signaler.first != VK_NULL_HANDLE) {
448125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is a queue -- use this as proof that prior operations on that queue have completed.
44829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, pFence->signaler.first), pFence->signaler.second);
4483bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    } else {
448425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is the WSI. We're not tracking what the WSI op actually /was/ in CV yet, but we need to mark
448525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // the fence as retired.
4486d4513979120463171eb479cdded9336eb9944da1Chris Forbes        pFence->state = FENCE_RETIRED;
4487d4513979120463171eb479cdded9336eb9944da1Chris Forbes    }
4488b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes}
4489b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes
4490accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlisstatic bool PreCallValidateWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences) {
4491cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.wait_for_fences) return false;
4492accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = false;
4493accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    for (uint32_t i = 0; i < fence_count; i++) {
4494accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        skip |= verifyWaitFenceState(dev_data, fences[i], "vkWaitForFences");
4495b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        skip |= VerifyQueueStateToFence(dev_data, fences[i]);
4496accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4497accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    return skip;
4498accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4499accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4500b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences, VkBool32 wait_all) {
4501b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    // When we know that all fences are complete we can clean/remove their CBs
4502accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    if ((VK_TRUE == wait_all) || (1 == fence_count)) {
4503accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        for (uint32_t i = 0; i < fence_count; i++) {
4504b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            RetireFence(dev_data, fences[i]);
4505accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        }
4506accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4507accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    // NOTE : Alternate case not handled here is when some fences have completed. In
4508accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    //  this case for app to guarantee which fences completed it will have to call
4509b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    //  vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
4510accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4511accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4512bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
4513bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint64_t timeout) {
451456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
45155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Verify fence status of submitted fences
4516b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4517accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = PreCallValidateWaitForFences(dev_data, fenceCount, pFences);
4518b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4519cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4520a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
45214a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.WaitForFences(device, fenceCount, pFences, waitAll, timeout);
4522414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller
45235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4524b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
4525b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordWaitForFences(dev_data, fenceCount, pFences, waitAll);
4526b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
45275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
45285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
45295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4531f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlisstatic bool PreCallValidateGetFenceStatus(layer_data *dev_data, VkFence fence) {
4532cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_fence_state) return false;
4533f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    return verifyWaitFenceState(dev_data, fence, "vkGetFenceStatus");
4534f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis}
4535f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
4536b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordGetFenceStatus(layer_data *dev_data, VkFence fence) { RetireFence(dev_data, fence); }
4537f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
453889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL GetFenceStatus(VkDevice device, VkFence fence) {
453956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4540b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4541f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    bool skip = PreCallValidateGetFenceStatus(dev_data, fence);
4542b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4543cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4544a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
45454a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetFenceStatus(device, fence);
45465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4547f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.lock();
4548b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordGetFenceStatus(dev_data, fence);
4549f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.unlock();
45505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
45515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
45525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
45543b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlisstatic void PostCallRecordGetDeviceQueue(layer_data *dev_data, uint32_t q_family_index, VkQueue queue) {
45553b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    // Add queue to tracking set only if it is new
45563b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    auto result = dev_data->queues.emplace(queue);
45573b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    if (result.second == true) {
455836c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        QUEUE_STATE *queue_state = &dev_data->queueMap[queue];
45593b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queue = queue;
45603b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queueFamilyIndex = q_family_index;
45613b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->seq = 0;
45623b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    }
45633b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis}
45643b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis
4565bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
456656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
45674a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
4568b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
4569b376edacad6f7ab3fcc0a914e9b1673a9fcd5143Mark Lobodzinski
45703b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    PostCallRecordGetDeviceQueue(dev_data, queueFamilyIndex, *pQueue);
45715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
457336c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool PreCallValidateQueueWaitIdle(layer_data *dev_data, VkQueue queue, QUEUE_STATE **queue_state) {
45749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *queue_state = GetQueueState(dev_data, queue);
4575cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.queue_wait_idle) return false;
4576e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    return VerifyQueueStateToSeq(dev_data, *queue_state, (*queue_state)->seq + (*queue_state)->submissions.size());
45774273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
45784273a1c157585a645dca4c960086032793899d05Tobin Ehlis
457936c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void PostCallRecordQueueWaitIdle(layer_data *dev_data, QUEUE_STATE *queue_state) {
4580e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    RetireWorkOnQueue(dev_data, queue_state, queue_state->seq + queue_state->submissions.size());
45814273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
45824273a1c157585a645dca4c960086032793899d05Tobin Ehlis
458389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueueWaitIdle(VkQueue queue) {
458456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
458536c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    QUEUE_STATE *queue_state = nullptr;
45869867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
45874273a1c157585a645dca4c960086032793899d05Tobin Ehlis    bool skip = PreCallValidateQueueWaitIdle(dev_data, queue, &queue_state);
45889867daedbf52debc77d6568162ee21e071699b80Chris Forbes    lock.unlock();
4589cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
45904a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueueWaitIdle(queue);
45914273a1c157585a645dca4c960086032793899d05Tobin Ehlis    if (VK_SUCCESS == result) {
4592e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.lock();
4593e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        PostCallRecordQueueWaitIdle(dev_data, queue_state);
4594e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.unlock();
45954273a1c157585a645dca4c960086032793899d05Tobin Ehlis    }
45965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
45975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
45998767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic bool PreCallValidateDeviceWaitIdle(layer_data *dev_data) {
4600cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.device_wait_idle) return false;
46018767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = false;
46028767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
46038767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
46048767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
46058767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    return skip;
46068767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
46078767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
46088767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic void PostCallRecordDeviceWaitIdle(layer_data *dev_data) {
46098767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
46108767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        RetireWorkOnQueue(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
46118767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
46128767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
46138767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
461489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL DeviceWaitIdle(VkDevice device) {
461556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4616b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
46178767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = PreCallValidateDeviceWaitIdle(dev_data);
4618b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4619cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
46204a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.DeviceWaitIdle(device);
46218767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    if (VK_SUCCESS == result) {
46228767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.lock();
46238767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        PostCallRecordDeviceWaitIdle(dev_data);
46248767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.unlock();
46258767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
46265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
46275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
46291d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic bool PreCallValidateDestroyFence(layer_data *dev_data, VkFence fence, FENCE_NODE **fence_node, VK_OBJECT *obj_struct) {
46309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *fence_node = GetFenceNode(dev_data, fence);
46319b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(fence), kVulkanObjectTypeFence};
4632cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_fence) return false;
46331d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = false;
46341d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (*fence_node) {
46351d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        if ((*fence_node)->state == FENCE_INFLIGHT) {
46361d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
4637315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(fence), __LINE__, VALIDATION_ERROR_24e008c0, "DS", "Fence 0x%" PRIx64 " is in use. %s",
4638315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(fence), validation_error_map[VALIDATION_ERROR_24e008c0]);
46391d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        }
46401d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
46411d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    return skip;
46421d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis}
46431d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
46441d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic void PostCallRecordDestroyFence(layer_data *dev_data, VkFence fence) { dev_data->fenceMap.erase(fence); }
46451d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
464689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
464756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
46481d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    // Common data objects used pre & post call
46491d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    FENCE_NODE *fence_node = nullptr;
46501d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    VK_OBJECT obj_struct;
4651b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
46521d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = PreCallValidateDestroyFence(dev_data, fence, &fence_node, &obj_struct);
46531344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
46541d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (!skip) {
46551d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.unlock();
46564a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyFence(device, fence, pAllocator);
46571d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.lock();
46581d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        PostCallRecordDestroyFence(dev_data, fence);
46591d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
46605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4662c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic bool PreCallValidateDestroySemaphore(layer_data *dev_data, VkSemaphore semaphore, SEMAPHORE_NODE **sema_node,
4663c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis                                            VK_OBJECT *obj_struct) {
46649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sema_node = GetSemaphoreNode(dev_data, semaphore);
46659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(semaphore), kVulkanObjectTypeSemaphore};
4666cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_semaphore) return false;
4667c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = false;
4668c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    if (*sema_node) {
4669315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sema_node, *obj_struct, VALIDATION_ERROR_268008e2);
4670c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    }
4671c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    return skip;
4672c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis}
4673c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
4674c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic void PostCallRecordDestroySemaphore(layer_data *dev_data, VkSemaphore sema) { dev_data->semaphoreMap.erase(sema); }
4675c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
4676bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
467756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4678c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    SEMAPHORE_NODE *sema_node;
4679c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    VK_OBJECT obj_struct;
4680e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
4681c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = PreCallValidateDestroySemaphore(dev_data, semaphore, &sema_node, &obj_struct);
4682eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis    if (!skip) {
4683eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        lock.unlock();
46844a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySemaphore(device, semaphore, pAllocator);
4685c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        lock.lock();
4686c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        PostCallRecordDestroySemaphore(dev_data, semaphore);
468799d938c90c2f000ee73fb13513dacf84ffa5651fMark Mueller    }
46885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
46904710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic bool PreCallValidateDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE **event_state, VK_OBJECT *obj_struct) {
46919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *event_state = GetEventNode(dev_data, event);
46929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(event), kVulkanObjectTypeEvent};
4693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_event) return false;
4694d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = false;
4695d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    if (*event_state) {
4696315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *event_state, *obj_struct, VALIDATION_ERROR_24c008f2);
4697d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    }
4698d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    return skip;
4699d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
4700d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
47014710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic void PostCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
470239c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, event_state->cb_bindings, obj_struct);
4703d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    dev_data->eventMap.erase(event);
4704d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
4705d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
470689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
470756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
47084710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    EVENT_STATE *event_state = nullptr;
4709d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    VK_OBJECT obj_struct;
4710b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4711d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = PreCallValidateDestroyEvent(dev_data, event, &event_state, &obj_struct);
4712f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
4713f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
47144a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyEvent(device, event, pAllocator);
4715d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        lock.lock();
4716405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (event != VK_NULL_HANDLE) {
4717405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyEvent(dev_data, event, event_state, obj_struct);
4718405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
4719f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
47205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
472283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlisstatic bool PreCallValidateDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE **qp_state,
472383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis                                            VK_OBJECT *obj_struct) {
47249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *qp_state = GetQueryPoolNode(dev_data, query_pool);
47259b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(query_pool), kVulkanObjectTypeQueryPool};
4726cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_query_pool) return false;
472783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = false;
472883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    if (*qp_state) {
4729315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *qp_state, *obj_struct, VALIDATION_ERROR_26200632);
473083c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    }
473183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    return skip;
473283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
473383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
4734bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void PostCallRecordDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE *qp_state,
4735bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VK_OBJECT obj_struct) {
473683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    invalidateCommandBuffers(dev_data, qp_state->cb_bindings, obj_struct);
473783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    dev_data->queryPoolMap.erase(query_pool);
473883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
473983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
4740bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
474156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
474283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    QUERY_POOL_NODE *qp_state = nullptr;
474383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    VK_OBJECT obj_struct;
4744ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
474583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = PreCallValidateDestroyQueryPool(dev_data, queryPool, &qp_state, &obj_struct);
4746f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
4747f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
47484a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyQueryPool(device, queryPool, pAllocator);
474983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        lock.lock();
4750405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (queryPool != VK_NULL_HANDLE) {
4751405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyQueryPool(dev_data, queryPool, qp_state, obj_struct);
4752405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
4753f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
47545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47559fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic bool PreCallValidateGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
47569fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               uint32_t query_count, VkQueryResultFlags flags,
47579fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
4758a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    // TODO: clean this up, it's insanely wasteful.
4759a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    for (auto cmd_buffer : dev_data->commandBufferMap) {
4760a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        if (cmd_buffer.second->in_use.load()) {
4761a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            for (auto query_state_pair : cmd_buffer.second->queryToStateMap) {
4762a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                (*queries_in_flight)[query_state_pair.first].push_back(
4763a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                    cmd_buffer.first);
4764a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            }
47655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4767cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_query_pool_results) return false;
47689fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = false;
47699fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
47709fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
47719fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
47729fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
47739fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
4774ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski            // Available and in flight
47759fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
47769fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
47779fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
47789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
47799fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
47809fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair == cb->waitedEventsBeforeQueryReset.end()) {
47819fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
47829fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
47839fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is in flight.",
47849b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(query_pool), first_query + i);
4785ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                    }
4786ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
4787ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable and in flight
47889fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
47899fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                       !query_state_pair->second) {
4790ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // TODO : Can there be the same query in use by multiple command buffers in flight?
4791ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                bool make_available = false;
47929fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
47939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
47949fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    make_available |= cb->queryToStateMap[query];
4795ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
4796ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) {
47979fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
47989fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
47999fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
48009b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(query_pool), first_query + i);
48015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
4802ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable
48039fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair != dev_data->queryToStateMap.end() && !query_state_pair->second) {
48049fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
48059fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
48069fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
48079b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(query_pool), first_query + i);
48089fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                // Uninitialized
48099fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair == dev_data->queryToStateMap.end()) {
48109fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
48119fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
48129fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64
48139fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                " with index %d as data has not been collected for this index.",
48149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(query_pool), first_query + i);
48155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
48165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
48175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
48189fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return skip;
48199fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
48209fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
48219fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic void PostCallRecordGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
48229fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              uint32_t query_count,
48239fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
48249fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
48259fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
48269fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
48279fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
48289fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
48299fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            // Available and in flight
48309fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
48319fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
48329fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
48339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
48349fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
48359fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair != cb->waitedEventsBeforeQueryReset.end()) {
48369fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        for (auto event : query_event_pair->second) {
48379fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                            dev_data->eventMap[event].needsSignaled = true;
48389fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        }
48399fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    }
48409fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                }
48419fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            }
48429fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        }
48439fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    }
48449fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
48459fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
48469fdee42cd357379efb9aa27f90beb75d1f824955Tobin EhlisVKAPI_ATTR VkResult VKAPI_CALL GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
48479fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                                   size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags) {
484856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
48499fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    unordered_map<QueryObject, vector<VkCommandBuffer>> queries_in_flight;
48509fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
48519fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = PreCallValidateGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, flags, &queries_in_flight);
4852b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4853cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
48549fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    VkResult result =
48559fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        dev_data->dispatch_table.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
48569fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.lock();
48579fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    PostCallRecordGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, &queries_in_flight);
48589fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.unlock();
48599fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return result;
48605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4862825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if given ranges intersect, else false
4863825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Prereq : For both ranges, range->end - range->start > 0. This case should have already resulted
4864825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  in an error so not checking that here
4865825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// pad_ranges bool indicates a linear and non-linear comparison which requires padding
48663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski// In the case where padding is required, if an alias is encountered then a validation error is reported and skip
48673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski//  may be set by the callback function so caller should merge in skip value if padding case is possible.
48682ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton// This check can be skipped by passing skip_checks=true, for call sites outside the validation path.
48693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinskistatic bool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, MEMORY_RANGE const *range2, bool *skip,
48702ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton                            bool skip_checks) {
48713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    *skip = false;
4872825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_start = range1->start;
4873825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_end = range1->end;
4874825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_start = range2->start;
4875825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_end = range2->end;
4876825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    VkDeviceSize pad_align = 1;
4877825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (range1->linear != range2->linear) {
4878825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        pad_align = dev_data->phys_dev_properties.properties.limits.bufferImageGranularity;
4879825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
4880cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_end & ~(pad_align - 1)) < (r2_start & ~(pad_align - 1))) return false;
4881cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_start & ~(pad_align - 1)) > (r2_end & ~(pad_align - 1))) return false;
488247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
48832ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton    if (!skip_checks && (range1->linear != range2->linear)) {
488453ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        // In linear vs. non-linear case, warn of aliasing
4885825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_linear_str = range1->linear ? "Linear" : "Non-linear";
4886825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_type_str = range1->image ? "image" : "buffer";
4887825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_linear_str = range2->linear ? "linear" : "non-linear";
4888825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_type_str = range2->image ? "image" : "buffer";
4889825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto obj_type = range1->image ? VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT : VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;
48903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        *skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, obj_type, range1->handle, 0,
48913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                         MEMTRACK_INVALID_ALIASING, "MEM", "%s %s 0x%" PRIx64 " is aliased with %s %s 0x%" PRIx64
48923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           " which may indicate a bug. For further info refer to the "
48933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "Buffer-Image Granularity section of the Vulkan specification. "
48943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "(https://www.khronos.org/registry/vulkan/specs/1.0-extensions/"
48953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "xhtml/vkspec.html#resources-bufferimagegranularity)",
48963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                         r1_linear_str, r1_type_str, range1->handle, r2_linear_str, r2_type_str, range2->handle);
489747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
4898825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Ranges intersect
4899825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    return true;
490047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
4901623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis// Simplified rangesIntersect that calls above function to check range1 for intersection with offset & end addresses
4902c3340a06ecac4d7b9540592cae339f8fc224d0b1Mark Lobodzinskibool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, VkDeviceSize offset, VkDeviceSize end) {
4903825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Create a local MEMORY_RANGE struct to wrap offset/size
4904825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    MEMORY_RANGE range_wrap;
4905825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Synch linear with range1 to avoid padding and potential validation error case
4906825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.linear = range1->linear;
4907825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.start = offset;
4908cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    range_wrap.end = end;
4909825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    bool tmp_bool;
49102ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton    return rangesIntersect(dev_data, range1, &range_wrap, &tmp_bool, true);
4911825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
4912cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given mem_info, set all ranges valid that intersect [offset-end] range
4913cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// TODO : For ranges where there is no alias, we may want to create new buffer ranges that are valid
4914cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlisstatic void SetMemRangesValid(layer_data const *dev_data, DEVICE_MEM_INFO *mem_info, VkDeviceSize offset, VkDeviceSize end) {
4915cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    bool tmp_bool = false;
4916f6e16b28b808a342cb92768001afa2cfeee08a11Tobin Ehlis    MEMORY_RANGE map_range = {};
4917cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.linear = true;
4918cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.start = offset;
4919cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.end = end;
4920cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    for (auto &handle_range_pair : mem_info->bound_ranges) {
49212ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &handle_range_pair.second, &map_range, &tmp_bool, false)) {
4922cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : WARN here if tmp_bool true?
4923cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            handle_range_pair.second.valid = true;
4924cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        }
4925cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    }
4926cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis}
49270ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
49280ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info,
49290ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                      VkDeviceSize memoryOffset, VkMemoryRequirements memRequirements, bool is_image,
49300ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                      bool is_linear, const char *api_name) {
49310ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    bool skip = false;
49320ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
49330ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    MEMORY_RANGE range;
49340ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.image = is_image;
49350ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.handle = handle;
49360ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.linear = is_linear;
49370ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.valid = mem_info->global_valid;
49380ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.memory = mem_info->mem;
49390ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.start = memoryOffset;
49400ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.size = memRequirements.size;
49410ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.end = memoryOffset + memRequirements.size - 1;
49420ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.aliases.clear();
49430ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
49440ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    // Check for aliasing problems.
49450ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    for (auto &obj_range_pair : mem_info->bound_ranges) {
49460ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto check_range = &obj_range_pair.second;
49470ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        bool intersection_error = false;
49482ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &range, check_range, &intersection_error, false)) {
49490ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= intersection_error;
49500ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            range.aliases.insert(check_range);
49510ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
49520ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    }
49530ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
49540ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    if (memoryOffset >= mem_info->alloc_info.allocationSize) {
4955315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        UNIQUE_VALIDATION_ERROR_CODE error_code = is_image ? VALIDATION_ERROR_1740082c : VALIDATION_ERROR_1700080e;
49560ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
49579b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(mem_info->mem), __LINE__, error_code, "MEM",
49580ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
49590ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       "), memoryOffset=0x%" PRIxLEAST64 " must be less than the memory allocation size 0x%" PRIxLEAST64 ". %s",
49609b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       api_name, HandleToUint64(mem_info->mem), handle, memoryOffset, mem_info->alloc_info.allocationSize,
49619b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       validation_error_map[error_code]);
49620ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    }
49630ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
49640ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    return skip;
49650ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
49660ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
4967825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Object with given handle is being bound to memory w/ given mem_info struct.
4968825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Track the newly bound memory range with given memoryOffset
4969825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Also scan any previous ranges, track aliased ranges with new range, and flag an error if a linear
4970825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  and non-linear range incorrectly overlap.
4971825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if an error is flagged and the user callback returns "true", otherwise false
4972825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_image indicates an image object, otherwise handle is for a buffer
4973825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_linear indicates a buffer or linear image
49740ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info, VkDeviceSize memoryOffset,
49750ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                              VkMemoryRequirements memRequirements, bool is_image, bool is_linear) {
49765360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    MEMORY_RANGE range;
4977825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
4978825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.image = is_image;
497947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.handle = handle;
4980825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.linear = is_linear;
4981f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis    range.valid = mem_info->global_valid;
4982825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.memory = mem_info->mem;
498347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.start = memoryOffset;
4984825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.size = memRequirements.size;
498547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.end = memoryOffset + memRequirements.size - 1;
49865360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    range.aliases.clear();
49875360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // Update Memory aliasing
498875f4c8cec0996021a4258b9bf920a9e0fea4eac1Tobin 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
49895360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // inserted into map before loop to get the final ptr, then we may enter loop when not needed & we check range against itself
49905360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    std::unordered_set<MEMORY_RANGE *> tmp_alias_ranges;
4991825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto &obj_range_pair : mem_info->bound_ranges) {
4992825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto check_range = &obj_range_pair.second;
49935360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        bool intersection_error = false;
49942ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &range, check_range, &intersection_error, true)) {
4995825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis            range.aliases.insert(check_range);
49965360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis            tmp_alias_ranges.insert(check_range);
4997825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        }
4998825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
49995360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    mem_info->bound_ranges[handle] = std::move(range);
50005360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    for (auto tmp_range : tmp_alias_ranges) {
50015360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        tmp_range->aliases.insert(&mem_info->bound_ranges[handle]);
50025360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    }
5003825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (is_image)
5004825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.insert(handle);
5005825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    else
5006825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.insert(handle);
500747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
500847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
50090ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info,
50100ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                           VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, bool is_linear,
50110ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                           const char *api_name) {
50129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    return ValidateInsertMemoryRange(dev_data, HandleToUint64(image), mem_info, mem_offset, mem_reqs, true, is_linear, api_name);
50130ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
50140ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
50150ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                   VkMemoryRequirements mem_reqs, bool is_linear) {
50169b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    InsertMemoryRange(dev_data, HandleToUint64(image), mem_info, mem_offset, mem_reqs, true, is_linear);
5017825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5018825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
50190ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info,
50200ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                            VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, const char *api_name) {
50219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    return ValidateInsertMemoryRange(dev_data, HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, false, true, api_name);
50220ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
50230ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
50240ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                    VkMemoryRequirements mem_reqs) {
50259b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    InsertMemoryRange(dev_data, HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, false, true);
5026825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5027825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5028825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Remove MEMORY_RANGE struct for give handle from bound_ranges of mem_info
5029825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  is_image indicates if handle is for image or buffer
5030825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  This function will also remove the handle-to-index mapping from the appropriate
5031825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  map and clean up any aliases for range being removed.
5032825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic void RemoveMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info, bool is_image) {
5033825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto erase_range = &mem_info->bound_ranges[handle];
5034825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto alias_range : erase_range->aliases) {
5035825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        alias_range->aliases.erase(erase_range);
503647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
50375360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    erase_range->aliases.clear();
5038825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    mem_info->bound_ranges.erase(handle);
50391cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    if (is_image) {
5040825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.erase(handle);
50411cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    } else {
5042825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.erase(handle);
50431cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    }
504447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
504547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
5046842b2d28ded1c6e2c38491a81213d0e1d1b7295aMark Lobodzinskivoid RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, false); }
5047825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
50488c59133586421be878d393799b30044497f77727Mark Lobodzinskivoid RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, true); }
5049825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5050bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
505156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5052e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
5053e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    VK_OBJECT obj_struct;
5054b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5055e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    bool skip = PreCallValidateDestroyBuffer(dev_data, buffer, &buffer_state, &obj_struct);
5056e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    if (!skip) {
5057b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
50584a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBuffer(device, buffer, pAllocator);
5059e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        lock.lock();
5060405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (buffer != VK_NULL_HANDLE) {
5061405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBuffer(dev_data, buffer, buffer_state, obj_struct);
5062405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
506347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
50645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5066bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
506756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5068f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
50698e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    BUFFER_VIEW_STATE *buffer_view_state = nullptr;
50708e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    VK_OBJECT obj_struct;
5071a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
50728e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    // Validate state before calling down chain, update common data if we'll be calling down chain
50738e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    bool skip = PreCallValidateDestroyBufferView(dev_data, bufferView, &buffer_view_state, &obj_struct);
507438e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis    if (!skip) {
507538e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis        lock.unlock();
50764a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBufferView(device, bufferView, pAllocator);
50778e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis        lock.lock();
5078405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (bufferView != VK_NULL_HANDLE) {
5079405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBufferView(dev_data, bufferView, buffer_view_state, obj_struct);
5080405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
50815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
50825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
50842a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
508556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
50861facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    IMAGE_STATE *image_state = nullptr;
50872a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    VK_OBJECT obj_struct;
50882a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
50892a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    bool skip = PreCallValidateDestroyImage(dev_data, image, &image_state, &obj_struct);
50902a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    if (!skip) {
5091f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        lock.unlock();
50924a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImage(device, image, pAllocator);
50932a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        lock.lock();
5094405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (image != VK_NULL_HANDLE) {
5095405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImage(dev_data, image, image_state, obj_struct);
5096405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
50975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
50985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
51004261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinskistatic bool ValidateMemoryTypes(const layer_data *dev_data, const DEVICE_MEM_INFO *mem_info, const uint32_t memory_type_bits,
5101f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                const char *funcName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
51023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5103de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis    if (((1 << mem_info->alloc_info.memoryTypeIndex) & memory_type_bits) == 0) {
51043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
51059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(mem_info->mem), __LINE__, msgCode, "MT",
51063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "%s(): MemoryRequirements->memoryTypeBits (0x%X) for this object type are not compatible with the memory "
51073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "type (0x%X) of this memory object 0x%" PRIx64 ". %s",
51089b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       funcName, memory_type_bits, mem_info->alloc_info.memoryTypeIndex, HandleToUint64(mem_info->mem),
51099b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       validation_error_map[msgCode]);
51104261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    }
51113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
51124261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski}
51134261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski
5114160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic bool PreCallValidateBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
5115160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                            VkDeviceSize memoryOffset) {
51169207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    bool skip = false;
51175cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
5118160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
51199207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // Track objects tied to memory
51209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t buffer_handle = HandleToUint64(buffer);
51217a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip = ValidateSetMemBinding(dev_data, mem, buffer_handle, kVulkanObjectTypeBuffer, "vkBindBufferMemory()");
51222eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (!buffer_state->memory_requirements_checked) {
51232eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // There's not an explicit requirement in the spec to call vkGetBufferMemoryRequirements() prior to calling
51249207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // BindBufferMemory, but it's implied in that memory being bound must conform with VkMemoryRequirements from
51259207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // vkGetBufferMemoryRequirements()
51269207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
51279207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle, __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
51289207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): Binding memory to buffer 0x%" PRIxLEAST64
51299207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but vkGetBufferMemoryRequirements() has not been called on that buffer.",
51309207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle);
51312eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // Make the call for them so we can verify the state
51322eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.unlock();
51339207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            dev_data->dispatch_table.GetBufferMemoryRequirements(dev_data->device, buffer, &buffer_state->requirements);
51342eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.lock();
51352eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        }
513647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
51370ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Validate bound memory range information
51389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
513957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
51400ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= ValidateInsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements,
51410ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                                    "vkBindBufferMemory()");
51429207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, buffer_state->requirements.memoryTypeBits, "vkBindBufferMemory()",
5143315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        VALIDATION_ERROR_17000816);
514447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
514547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
51462c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate memory requirements alignment
514716769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(memoryOffset, buffer_state->requirements.alignment) != 0) {
5148f60e41965223825191505eebc96491bb52e494a2Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5149315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            buffer_handle, __LINE__, VALIDATION_ERROR_17000818, "DS",
51509207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64
51519207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but must be an integer multiple of the "
51529207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
51539207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
5154315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            memoryOffset, buffer_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_17000818]);
51552c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
5156ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5157160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements size
5158160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        if (buffer_state->requirements.size > (mem_info->alloc_info.allocationSize - memoryOffset)) {
5159160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5160315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            buffer_handle, __LINE__, VALIDATION_ERROR_1700081a, "DS",
5161160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindBufferMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
5162160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be at least as large as "
5163160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
5164160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
5165160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            mem_info->alloc_info.allocationSize - memoryOffset, buffer_state->requirements.size,
5166315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1700081a]);
5167160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
5168160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
51692c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate device limits alignments
5170ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        static const VkBufferUsageFlagBits usage_list[3] = {
5171ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
5172bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT};
5173bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *memory_type[3] = {"texel", "uniform", "storage"};
5174bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *offset_name[3] = {"minTexelBufferOffsetAlignment", "minUniformBufferOffsetAlignment",
5175bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             "minStorageBufferOffsetAlignment"};
5176cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
51779207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // TODO:  vk_validation_stats.py cannot abide braces immediately preceding or following a validation error enum
5178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format off
5179315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        static const UNIQUE_VALIDATION_ERROR_CODE msgCode[3] = { VALIDATION_ERROR_17000810, VALIDATION_ERROR_17000812,
5180315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            VALIDATION_ERROR_17000814 };
5181cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format on
5182ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5183ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        // Keep this one fresh!
5184ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        const VkDeviceSize offset_requirement[3] = {
5185ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment,
5186ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
5187bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment};
51888718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        VkBufferUsageFlags usage = dev_data->bufferMap[buffer].get()->createInfo.usage;
5189ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5190ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        for (int i = 0; i < 3; i++) {
5191ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            if (usage & usage_list[i]) {
519216769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                if (SafeModulo(memoryOffset, offset_requirement[i]) != 0) {
51939207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                    skip |= log_msg(
5194f60e41965223825191505eebc96491bb52e494a2Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, buffer_handle,
5195cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, msgCode[i], "DS", "vkBindBufferMemory(): %s memoryOffset is 0x%" PRIxLEAST64
5196cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    " but must be a multiple of "
5197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    "device limit %s 0x%" PRIxLEAST64 ". %s",
5198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        memory_type[i], memoryOffset, offset_name[i], offset_requirement[i], validation_error_map[msgCode[i]]);
5199ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                }
52002c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves            }
52012c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
52025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
52039207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    return skip;
52049207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
52059207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
5206160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic void PostCallRecordBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
5207160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                           VkDeviceSize memoryOffset) {
52089207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (buffer_state) {
5209160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
52100ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Track bound memory range information
52110ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto mem_info = GetMemObjInfo(dev_data, mem);
52120ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        if (mem_info) {
52130ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            InsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements);
52140ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
52150ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
5216c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
52179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t buffer_handle = HandleToUint64(buffer);
52187a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        SetMemBinding(dev_data, mem, buffer_handle, kVulkanObjectTypeBuffer, "vkBindBufferMemory()");
5219c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
52209207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.mem = mem;
52219207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.offset = memoryOffset;
52229207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.size = buffer_state->requirements.size;
52239207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    }
52249207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
52259207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
52269207132ef623d47fcbdfeb9ebc796eade35a2f4cCort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
52279207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
52289207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
5229160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    auto buffer_state = GetBufferState(dev_data, buffer);
5230160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    bool skip = PreCallValidateBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
52319207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (!skip) {
52324a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.BindBufferMemory(device, buffer, mem, memoryOffset);
52339207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        if (result == VK_SUCCESS) {
5234160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            PostCallRecordBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
52359207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        }
52365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
52375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
52385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5240bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
5241bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       VkMemoryRequirements *pMemoryRequirements) {
524256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
524315caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
52449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
524515caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (buffer_state) {
524615caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        buffer_state->requirements = *pMemoryRequirements;
52472eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        buffer_state->memory_requirements_checked = true;
524815caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
52495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5251bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
525256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
525315caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetImageMemoryRequirements(device, image, pMemoryRequirements);
52549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, image);
525515caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (image_state) {
525615caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        image_state->requirements = *pMemoryRequirements;
52572eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        image_state->memory_requirements_checked = true;
525815caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
52595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5260593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
5261bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
526256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5263f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
5264f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    IMAGE_VIEW_STATE *image_view_state = nullptr;
5265f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    VK_OBJECT obj_struct;
5266a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5267f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    bool skip = PreCallValidateDestroyImageView(dev_data, imageView, &image_view_state, &obj_struct);
5268d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    if (!skip) {
5269d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis        lock.unlock();
52704a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImageView(device, imageView, pAllocator);
5271f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis        lock.lock();
5272405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (imageView != VK_NULL_HANDLE) {
5273405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImageView(dev_data, imageView, image_view_state, obj_struct);
5274405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5275d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    }
52765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5278bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyShaderModule(VkDevice device, VkShaderModule shaderModule,
5279bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               const VkAllocationCallbacks *pAllocator) {
528056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5281918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
5282b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
528351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->shaderModuleMap.erase(shaderModule);
5284b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5285918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
528651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->dispatch_table.DestroyShaderModule(device, shaderModule, pAllocator);
52875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
52894c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool PreCallValidateDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE **pipeline_state,
52908bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                           VK_OBJECT *obj_struct) {
529194165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *pipeline_state = getPipelineState(dev_data, pipeline);
52929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(pipeline), kVulkanObjectTypePipeline};
5293cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_pipeline) return false;
52948bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = false;
52958bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    if (*pipeline_state) {
5296315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *pipeline_state, *obj_struct, VALIDATION_ERROR_25c005fa);
52978bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    }
52988bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    return skip;
52998bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
53008bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
53014c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void PostCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
53028bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                          VK_OBJECT obj_struct) {
53038bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    // Any bound cmd buffers are now invalid
530439c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, pipeline_state->cb_bindings, obj_struct);
53058bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    dev_data->pipelineMap.erase(pipeline);
53068bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
53078bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
5308bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
530956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
53104c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pipeline_state = nullptr;
53118bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    VK_OBJECT obj_struct;
5312e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
53138bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = PreCallValidateDestroyPipeline(dev_data, pipeline, &pipeline_state, &obj_struct);
5314f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5315f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
53164a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyPipeline(device, pipeline, pAllocator);
53178bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis        lock.lock();
5318405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (pipeline != VK_NULL_HANDLE) {
5319405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyPipeline(dev_data, pipeline, pipeline_state, obj_struct);
5320405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5321f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
53225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5324bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout,
5325bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
532656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5327e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
53286792ea7cc0ce5fa64b7bd6c946460608cbda91c7Tobin Ehlis    dev_data->pipelineLayoutMap.erase(pipelineLayout);
5329e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    lock.unlock();
5330e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
53314a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineLayout(device, pipelineLayout, pAllocator);
53325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5334d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic bool PreCallValidateDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE **sampler_state,
5335806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                          VK_OBJECT *obj_struct) {
53369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sampler_state = GetSamplerState(dev_data, sampler);
53379b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(sampler), kVulkanObjectTypeSampler};
5338cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_sampler) return false;
5339806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = false;
5340806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    if (*sampler_state) {
5341315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sampler_state, *obj_struct, VALIDATION_ERROR_26600874);
5342806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    }
5343806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    return skip;
5344806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5345806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5346d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic void PostCallRecordDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE *sampler_state,
5347806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                         VK_OBJECT obj_struct) {
5348806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    // Any bound cmd buffers are now invalid
5349cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (sampler_state) invalidateCommandBuffers(dev_data, sampler_state->cb_bindings, obj_struct);
5350806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    dev_data->samplerMap.erase(sampler);
5351806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5352806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5353bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
535456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5355d31a44af6da568692a73201825459689c9431867Tobin Ehlis    SAMPLER_STATE *sampler_state = nullptr;
5356806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    VK_OBJECT obj_struct;
535756f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5358806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = PreCallValidateDestroySampler(dev_data, sampler, &sampler_state, &obj_struct);
5359f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5360f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
53614a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySampler(device, sampler, pAllocator);
5362806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        lock.lock();
5363405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (sampler != VK_NULL_HANDLE) {
5364405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroySampler(dev_data, sampler, sampler_state, obj_struct);
5365405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5366f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
53675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
536979c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlisstatic void PostCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDescriptorSetLayout ds_layout) {
537079c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->descriptorSetLayoutMap.erase(ds_layout);
537179c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis}
537279c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis
5373bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
5374bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator) {
537556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
537679c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->dispatch_table.DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
537779c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
537879c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    PostCallRecordDestroyDescriptorSetLayout(dev_data, descriptorSetLayout);
53795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5381c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic bool PreCallValidateDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool pool,
5382a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                 DESCRIPTOR_POOL_STATE **desc_pool_state, VK_OBJECT *obj_struct) {
53839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *desc_pool_state = GetDescriptorPoolState(dev_data, pool);
53849b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(pool), kVulkanObjectTypeDescriptorPool};
5385cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_descriptor_pool) return false;
5386c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = false;
5387c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (*desc_pool_state) {
5388315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *desc_pool_state, *obj_struct, VALIDATION_ERROR_2440025e);
5389c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5390c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    return skip;
5391c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5392c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5393c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic void PostCallRecordDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool descriptorPool,
5394a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                DESCRIPTOR_POOL_STATE *desc_pool_state, VK_OBJECT obj_struct) {
5395c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Any bound cmd buffers are now invalid
539639c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, desc_pool_state->cb_bindings, obj_struct);
5397c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Free sets that were in this pool
5398c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    for (auto ds : desc_pool_state->sets) {
5399c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        freeDescriptorSet(dev_data, ds);
5400c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5401c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    dev_data->descriptorPoolMap.erase(descriptorPool);
5402c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5403c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5404bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
5405bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
540656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5407a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    DESCRIPTOR_POOL_STATE *desc_pool_state = nullptr;
5408c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    VK_OBJECT obj_struct;
5409c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5410c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = PreCallValidateDestroyDescriptorPool(dev_data, descriptorPool, &desc_pool_state, &obj_struct);
5411c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (!skip) {
5412c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.unlock();
5413c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        dev_data->dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
5414c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.lock();
5415405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptorPool != VK_NULL_HANDLE) {
5416405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyDescriptorPool(dev_data, descriptorPool, desc_pool_state, obj_struct);
5417405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5418c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
54195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski// Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip result
5421bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If this is a secondary command buffer, then make sure its primary is also in-flight
5422bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If primary is not in-flight, then remove secondary from global in-flight set
5423bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// This function is only valid at a point when cmdBuffer is being reset or freed
5424cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action,
5425cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
54263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5427a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    if (cb_node->in_use.load()) {
5428a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5429a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                        HandleToUint64(cb_node->commandBuffer), __LINE__, error_code, "DS",
5430a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                        "Attempt to %s command buffer (0x%p) which is in use. %s", action, cb_node->commandBuffer,
5431a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                        validation_error_map[error_code]);
5432bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
54333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
5434bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
5435a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
5436bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Iterate over all cmdBuffers in given commandPool and verify that each is not in use
5437cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool, const char *action,
5438cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                        UNIQUE_VALIDATION_ERROR_CODE error_code) {
54393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5440a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
5441a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        skip |= checkCommandBufferInFlight(dev_data, GetCBNode(dev_data, cmd_buffer), action, error_code);
5442bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
54433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
5444bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
54455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5446bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
5447bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
544856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
54493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5450b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5451c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
54525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < commandBufferCount; i++) {
54539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
54545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Delete CB information structure, and remove from commandBufferMap
54559f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
5456315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= checkCommandBufferInFlight(dev_data, cb_node, "free", VALIDATION_ERROR_2840005e);
5457c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        }
5458c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    }
5459c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
54603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
5461c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
54629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
5463c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    for (uint32_t i = 0; i < commandBufferCount; i++) {
54649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
5465c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        // Delete CB information structure, and remove from commandBufferMap
54669f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
54675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // reset prior to delete for data clean-up
5468a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            // TODO: fix this, it's insane.
54699f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            resetCB(dev_data, cb_node->commandBuffer);
54709f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->commandBufferMap.erase(cb_node->commandBuffer);
54719f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            delete cb_node;
54725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
54735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Remove commandBuffer reference from commandPoolMap
5475c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        pPool->commandBuffers.remove(pCommandBuffers[i]);
54765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5477b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5478e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
54794a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
54805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
548289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
5483bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
548456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
54855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54864a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
54875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5489b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
54905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
54915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
54925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
54935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
54945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
549689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
549789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
549856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
54990c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    bool skip = false;
55000c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (pCreateInfo && pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
55010c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        if (!dev_data->enabled_features.pipelineStatisticsQuery) {
55020c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
5503315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_11c0062e, "DS",
55040c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "Query pool with type VK_QUERY_TYPE_PIPELINE_STATISTICS created on a device "
55050c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "with VkDeviceCreateInfo.pEnabledFeatures.pipelineStatisticsQuery == VK_FALSE. %s",
5506315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_11c0062e]);
55070c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        }
55080c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
55090c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis
55100c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
55110c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (!skip) {
55120c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        result = dev_data->dispatch_table.CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
55130c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
55145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
5515b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5516eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        QUERY_POOL_NODE *qp_node = &dev_data->queryPoolMap[*pQueryPool];
5517eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        qp_node->createInfo = *pCreateInfo;
55185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
55195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
55205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
55225f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic bool PreCallValidateDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE **cp_state) {
55239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cp_state = GetCommandPoolNode(dev_data, pool);
5524cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_command_pool) return false;
55255f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = false;
55265f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (*cp_state) {
55275f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        // Verify that command buffers in pool are complete (not in-flight)
5528315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= checkCommandBuffersInFlight(dev_data, *cp_state, "destroy command pool with", VALIDATION_ERROR_24000052);
55295f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
55305f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    return skip;
55315f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
55325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
55335f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic void PostCallRecordDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE *cp_state) {
55349f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandBufferMap
55355f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    for (auto cb : cp_state->commandBuffers) {
55369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, cb);
55377b34d10b918c1f69e7252174965c6a7a7c35ae05Chris Forbes        clear_cmd_buf_and_mem_references(dev_data, cb_node);
5538d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // Remove references to this cb_node prior to delete
5539d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // TODO : Need better solution here, resetCB?
55407165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        for (auto obj : cb_node->object_bindings) {
55417165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski            removeCommandBufferBinding(dev_data, &obj, cb_node);
55427165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        }
5543d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        for (auto framebuffer : cb_node->framebuffers) {
55449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
5545cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(cb_node);
5546d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        }
5547cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        dev_data->commandBufferMap.erase(cb);  // Remove this command buffer
5548cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        delete cb_node;                        // delete CB info structure
5549a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    }
55505f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    dev_data->commandPoolMap.erase(pool);
55515f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
5552e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
55535f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis// Destroy commandPool along with all of the commandBuffers allocated from that pool
55545f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
555556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
55565f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    COMMAND_POOL_NODE *cp_state = nullptr;
55575f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
55585f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = PreCallValidateDestroyCommandPool(dev_data, commandPool, &cp_state);
55595f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (!skip) {
55605f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.unlock();
55615f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        dev_data->dispatch_table.DestroyCommandPool(device, commandPool, pAllocator);
55625f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.lock();
5563405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (commandPool != VK_NULL_HANDLE) {
5564405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyCommandPool(dev_data, commandPool, cp_state);
5565405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
55665f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
55675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5569bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
557056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
55713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5572400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
55731ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
55749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
5575315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= checkCommandBuffersInFlight(dev_data, pPool, "reset command pool with", VALIDATION_ERROR_32800050);
55761ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    lock.unlock();
5577a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes
55783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
55795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
55804a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandPool(device, commandPool, flags);
55815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
55825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Reset all of the CBs allocated from this pool
55835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
55841ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.lock();
5585a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        for (auto cmdBuffer : pPool->commandBuffers) {
5586a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes            resetCB(dev_data, cmdBuffer);
55875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
55881ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.unlock();
55895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
55905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
55915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
559389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
559456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
55953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5596b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
55975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < fenceCount; ++i) {
55989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, pFences[i]);
5599090da73358f71ba026e2474a822fecf55267d166Chris Forbes        if (pFence && pFence->state == FENCE_INFLIGHT) {
5600315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |=
5601315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5602315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pFences[i]), __LINE__, VALIDATION_ERROR_32e008c6, "DS", "Fence 0x%" PRIx64 " is in use. %s",
5603315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pFences[i]), validation_error_map[VALIDATION_ERROR_32e008c6]);
56045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
56055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5606b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5607090da73358f71ba026e2474a822fecf55267d166Chris Forbes
56083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
5609090da73358f71ba026e2474a822fecf55267d166Chris Forbes
56104a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetFences(device, fenceCount, pFences);
5611090da73358f71ba026e2474a822fecf55267d166Chris Forbes
5612090da73358f71ba026e2474a822fecf55267d166Chris Forbes    if (result == VK_SUCCESS) {
5613090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.lock();
5614090da73358f71ba026e2474a822fecf55267d166Chris Forbes        for (uint32_t i = 0; i < fenceCount; ++i) {
56159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pFence = GetFenceNode(dev_data, pFences[i]);
5616090da73358f71ba026e2474a822fecf55267d166Chris Forbes            if (pFence) {
5617090da73358f71ba026e2474a822fecf55267d166Chris Forbes                pFence->state = FENCE_UNSIGNALED;
5618090da73358f71ba026e2474a822fecf55267d166Chris Forbes            }
5619090da73358f71ba026e2474a822fecf55267d166Chris Forbes        }
5620090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.unlock();
5621090da73358f71ba026e2474a822fecf55267d166Chris Forbes    }
5622090da73358f71ba026e2474a822fecf55267d166Chris Forbes
56235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
56245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5626e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis// For given cb_nodes, invalidate them and track object causing invalidation
56270a4087f99558069e9f6a437ff2dbb5a9c1c22ccaTobin Ehlisvoid invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj) {
5628e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    for (auto cb_node : cb_nodes) {
562939c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        if (cb_node->state == CB_RECORDING) {
563039c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
56319b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
5632226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "Invalidating a command buffer that's currently being recorded: 0x%p.", cb_node->commandBuffer);
563339c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        }
5634e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->state = CB_INVALID;
5635e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->broken_bindings.push_back(obj);
5636db365f522319df6446b50584277a3bbfee1c1052Chris Forbes
5637db365f522319df6446b50584277a3bbfee1c1052Chris Forbes        // if secondary, then propagate the invalidation to the primaries that will call us.
5638db365f522319df6446b50584277a3bbfee1c1052Chris Forbes        if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {
5639db365f522319df6446b50584277a3bbfee1c1052Chris Forbes            invalidateCommandBuffers(dev_data, cb_node->linkedCommandBuffers, obj);
5640db365f522319df6446b50584277a3bbfee1c1052Chris Forbes        }
5641e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    }
5642e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis}
5643e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis
5644c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool PreCallValidateDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer,
5645c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis                                              FRAMEBUFFER_STATE **framebuffer_state, VK_OBJECT *obj_struct) {
56469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *framebuffer_state = GetFramebufferState(dev_data, framebuffer);
56479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(framebuffer), kVulkanObjectTypeFramebuffer};
5648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_framebuffer) return false;
5649728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = false;
5650728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (*framebuffer_state) {
5651315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *framebuffer_state, *obj_struct, VALIDATION_ERROR_250006f8);
5652728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    }
5653728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    return skip;
5654728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
5655728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
5656c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void PostCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
5657728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis                                             VK_OBJECT obj_struct) {
565839c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, framebuffer_state->cb_bindings, obj_struct);
5659728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    dev_data->frameBufferMap.erase(framebuffer);
5660728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
5661728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
5662bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
566356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5664c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    FRAMEBUFFER_STATE *framebuffer_state = nullptr;
5665728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    VK_OBJECT obj_struct;
5666b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5667728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = PreCallValidateDestroyFramebuffer(dev_data, framebuffer, &framebuffer_state, &obj_struct);
5668728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (!skip) {
5669728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.unlock();
5670728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        dev_data->dispatch_table.DestroyFramebuffer(device, framebuffer, pAllocator);
5671728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.lock();
5672405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (framebuffer != VK_NULL_HANDLE) {
5673405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyFramebuffer(dev_data, framebuffer, framebuffer_state, obj_struct);
5674405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
56755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
56765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
56780ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic bool PreCallValidateDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE **rp_state,
56790ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                             VK_OBJECT *obj_struct) {
56809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *rp_state = GetRenderPassState(dev_data, render_pass);
56819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(render_pass), kVulkanObjectTypeRenderPass};
5682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_renderpass) return false;
56830ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = false;
56840ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    if (*rp_state) {
5685315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *rp_state, *obj_struct, VALIDATION_ERROR_264006d2);
56860ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    }
56870ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    return skip;
56880ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
56890ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
56900ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic void PostCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
56910ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                            VK_OBJECT obj_struct) {
569239c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, rp_state->cb_bindings, obj_struct);
56930ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    dev_data->renderPassMap.erase(render_pass);
56940ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
56950ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
5696bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
569756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
56980ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    RENDER_PASS_STATE *rp_state = nullptr;
56990ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    VK_OBJECT obj_struct;
5700e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
57010ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = PreCallValidateDestroyRenderPass(dev_data, renderPass, &rp_state, &obj_struct);
5702a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    if (!skip) {
5703a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis        lock.unlock();
57044a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
57050ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        lock.lock();
5706405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (renderPass != VK_NULL_HANDLE) {
5707405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyRenderPass(dev_data, renderPass, rp_state, obj_struct);
5708405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5709a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    }
57105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
571289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
571389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
571456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
57153683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
57163683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    bool skip = PreCallValidateCreateBuffer(dev_data, pCreateInfo);
57173683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    lock.unlock();
57183683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
57193683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
57204a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
57215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
57225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
57233683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.lock();
57243683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBuffer(dev_data, pCreateInfo, pBuffer);
57253683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.unlock();
57265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
57275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
57285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
573089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
573189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
573256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
57338c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
57343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateCreateBufferView(dev_data, pCreateInfo);
57358c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
57363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
57374a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBufferView(device, pCreateInfo, pAllocator, pView);
57385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
57398c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
57403683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBufferView(dev_data, pCreateInfo, pView);
57418c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
57425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
57435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
57445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
57468dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski// Access helper functions for external modules
5747d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkFormatProperties *GetFormatProperties(core_validation::layer_data *device_data, VkFormat format) {
5748d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkFormatProperties *format_properties = new VkFormatProperties;
5749d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
5750d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
5751d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, format_properties);
5752d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return format_properties;
57538dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
57548dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
5755d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkImageFormatProperties *GetImageFormatProperties(core_validation::layer_data *device_data, VkFormat format,
5756d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageType image_type, VkImageTiling tiling, VkImageUsageFlags usage,
5757d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageCreateFlags flags) {
5758d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkImageFormatProperties *image_format_properties = new VkImageFormatProperties;
5759d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
5760d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
5761d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceImageFormatProperties(device_data->physical_device, format, image_type, tiling,
5762d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                                         usage, flags, image_format_properties);
5763d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return image_format_properties;
57648dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
57658dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
57667a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlisconst debug_report_data *GetReportData(const core_validation::layer_data *device_data) { return device_data->report_data; }
57678dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
57688dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinskiconst VkPhysicalDeviceProperties *GetPhysicalDeviceProperties(core_validation::layer_data *device_data) {
57698dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    return &device_data->phys_dev_props;
57708dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
57718dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
57728c59133586421be878d393799b30044497f77727Mark Lobodzinskiconst CHECK_DISABLED *GetDisables(core_validation::layer_data *device_data) { return &device_data->instance_data->disabled; }
57738c59133586421be878d393799b30044497f77727Mark Lobodzinski
57748c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> *GetImageMap(core_validation::layer_data *device_data) {
57758c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageMap;
57768c59133586421be878d393799b30044497f77727Mark Lobodzinski}
57778c59133586421be878d393799b30044497f77727Mark Lobodzinski
57788c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *GetImageSubresourceMap(core_validation::layer_data *device_data) {
57798c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageSubresourceMap;
57808c59133586421be878d393799b30044497f77727Mark Lobodzinski}
57818c59133586421be878d393799b30044497f77727Mark Lobodzinski
57828c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *GetImageLayoutMap(layer_data *device_data) {
57838c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageLayoutMap;
57848c59133586421be878d393799b30044497f77727Mark Lobodzinski}
57858c59133586421be878d393799b30044497f77727Mark Lobodzinski
57860db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlisstd::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const *GetImageLayoutMap(layer_data const *device_data) {
57870db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis    return &device_data->imageLayoutMap;
57880db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis}
57890db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis
57903683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>> *GetBufferMap(layer_data *device_data) {
57913683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferMap;
57923683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
57933683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
57943683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>> *GetBufferViewMap(layer_data *device_data) {
57953683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferViewMap;
57963683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
57973683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
57981c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinskistd::unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>> *GetImageViewMap(layer_data *device_data) {
57991c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski    return &device_data->imageViewMap;
58001c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski}
58011c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski
5802d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst PHYS_DEV_PROPERTIES_NODE *GetPhysDevProperties(const layer_data *device_data) {
58036a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    return &device_data->phys_dev_properties;
58046a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski}
58056a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski
58065f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinskiconst VkPhysicalDeviceFeatures *GetEnabledFeatures(const layer_data *device_data) {
58075f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski    return &device_data->enabled_features;
58085f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski}
58095f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski
5810a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinskiconst DeviceExtensions *GetDeviceExtensions(const layer_data *device_data) { return &device_data->extensions; }
58110e2296e24065d02615ee87561bbb80af414a1ddfMike Schuchardt
581289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
581389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
58148dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
581556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58168dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    bool skip = PreCallValidateCreateImage(dev_data, pCreateInfo, pAllocator, pImage);
58178dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    if (!skip) {
58188dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski        result = dev_data->dispatch_table.CreateImage(device, pCreateInfo, pAllocator, pImage);
58198dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    }
58205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5821b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5822920311b6aa5614a545cad59521770d0898a75d65Mark Lobodzinski        PostCallRecordCreateImage(dev_data, pCreateInfo, pImage);
58235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58278c07a094dc9cc4afb6b62181f341c12b9e969041Mark YoungVKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
58288c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
582956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58308c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
5831e3effabf8e97cae8e006477806ceaca62e4f2ce7Tobin Ehlis    bool skip = PreCallValidateCreateImageView(dev_data, pCreateInfo);
58328c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
5833cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
58344a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateImageView(device, pCreateInfo, pAllocator, pView);
58355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
58368c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
583779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        PostCallRecordCreateImageView(dev_data, pCreateInfo, *pView);
58388c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
58395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5840bb6624cb996175d8945190886a200e720b3871efChris Forbes
58415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5844bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo,
5845bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
584656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58474a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFence(device, pCreateInfo, pAllocator, pFence);
58485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5849b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5850a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        auto &fence_node = dev_data->fenceMap[*pFence];
58518988ad37ea5a054ff2ae3cbe4b767ae6c13cf48bChris Forbes        fence_node.fence = *pFence;
5852a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        fence_node.createInfo = *pCreateInfo;
5853cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        fence_node.state = (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) ? FENCE_RETIRED : FENCE_UNSIGNALED;
58545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO handle pipeline caches
585989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
586089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
586156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58624a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
58635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5866bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache,
5867bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkAllocationCallbacks *pAllocator) {
586856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58694a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineCache(device, pipelineCache, pAllocator);
58705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5872bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize,
5873bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    void *pData) {
587456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58754a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
58765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5879bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount,
5880bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   const VkPipelineCache *pSrcCaches) {
588156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58824a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
58835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58863d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis// utility function to set collective state for pipeline
58874c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisvoid set_pipeline_state(PIPELINE_STATE *pPipe) {
58883d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // If any attachment used by this pipeline has blendEnable, set top-level blendEnable
58893d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->graphicsPipelineCI.pColorBlendState) {
58903d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        for (size_t i = 0; i < pPipe->attachments.size(); ++i) {
58913d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (VK_TRUE == pPipe->attachments[i].blendEnable) {
58923d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                if (((pPipe->attachments[i].dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
58933d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
58943d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
58953d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
58963d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
58973d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
58983d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
58993d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
59003d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    pPipe->blendConstantsEnabled = true;
59013d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                }
59023d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            }
59033d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        }
59043d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
59053d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis}
59063d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis
5907daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinskibool validate_dual_src_blend_feature(layer_data *device_data, PIPELINE_STATE *pipe_state) {
5908daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    bool skip = false;
5909daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    if (pipe_state->graphicsPipelineCI.pColorBlendState) {
5910daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski        for (size_t i = 0; i < pipe_state->attachments.size(); ++i) {
5911daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            if (!device_data->enabled_features.dualSrcBlend) {
5912daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                if ((pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
5913daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
5914daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
5915daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA) ||
5916daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
5917daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
5918daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
5919daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA)) {
5920daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    skip |=
5921daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
59229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pipe_state->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
5923daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                "CmdBindPipeline: vkPipeline (0x%" PRIxLEAST64 ") attachment[" PRINTF_SIZE_T_SPECIFIER
5924daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                "] has a dual-source blend factor but this device feature is not enabled.",
59259b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pipe_state->pipeline), i);
5926daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                }
5927daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            }
5928daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski        }
5929daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    }
5930daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    return skip;
5931daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski}
5932daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski
593348b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinskistatic bool PreCallCreateGraphicsPipelines(layer_data *device_data, uint32_t count,
593448b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski                                           const VkGraphicsPipelineCreateInfo *create_infos, vector<PIPELINE_STATE *> &pipe_state) {
593548b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    bool skip = false;
5936bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    instance_layer_data *instance_data =
593756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
593848b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
593948b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    for (uint32_t i = 0; i < count; i++) {
594048b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski        skip |= verifyPipelineCreateState(device_data, pipe_state, i);
594178b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        if (create_infos[i].pVertexInputState != NULL) {
594278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            for (uint32_t j = 0; j < create_infos[i].pVertexInputState->vertexAttributeDescriptionCount; j++) {
594378b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormat format = create_infos[i].pVertexInputState->pVertexAttributeDescriptions[j].format;
594478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                // Internal call to get format info.  Still goes through layers, could potentially go directly to ICD.
594578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormatProperties properties;
594678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, &properties);
594778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                if ((properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0) {
594878b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                    skip |= log_msg(
594978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
5950315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        __LINE__, VALIDATION_ERROR_14a004de, "IMAGE",
595178b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "vkCreateGraphicsPipelines: pCreateInfo[%d].pVertexInputState->vertexAttributeDescriptions[%d].format "
595278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "(%s) is not a supported vertex buffer format. %s",
5953315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        i, j, string_VkFormat(format), validation_error_map[VALIDATION_ERROR_14a004de]);
595478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                }
595578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            }
595678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        }
595748b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    }
595848b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    return skip;
595948b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski}
596048b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
5961bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
5962bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
5963bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
59645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO What to do with pipelineCache?
59655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // The order of operations here is a little convoluted but gets the job done
59664c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    //  1. Pipeline create state is first shadowed into PIPELINE_STATE struct
59675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  2. Create state is then validated (which uses flags setup during shadowing)
59685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
596942486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    bool skip = false;
59705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
597142486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    vector<PIPELINE_STATE *> pipe_state(count);
597256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
59735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
5975b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
59765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
597842486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i] = new PIPELINE_STATE;
597942486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->initGraphicsPipeline(&pCreateInfos[i]);
59809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        pipe_state[i]->render_pass_ci.initialize(GetRenderPassState(dev_data, pCreateInfos[i].renderPass)->createInfo.ptr());
598142486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
59825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
598342486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    skip |= PreCallCreateGraphicsPipelines(dev_data, count, pCreateInfos, pipe_state);
59845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5985c70226063be6148056ceeccf835175a1fd59f24fChris Forbes    if (skip) {
5986c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        for (i = 0; i < count; i++) {
5987c70226063be6148056ceeccf835175a1fd59f24fChris Forbes            delete pipe_state[i];
59881ab616b32d4e5b7d62d4a8c41b0c03ea335ab845Chris Forbes            pPipelines[i] = VK_NULL_HANDLE;
5989c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        }
59907a456d188475c23b566334be45dc0489b2789653Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
59917a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
59927a456d188475c23b566334be45dc0489b2789653Chris Forbes
59937a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
5994bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
5995bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
59967a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
59977a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
599861943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
599961943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            delete pipe_state[i];
6000bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
600161943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            pipe_state[i]->pipeline = pPipelines[i];
600261943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            dev_data->pipelineMap[pipe_state[i]->pipeline] = pipe_state[i];
600361943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        }
60045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6005c70226063be6148056ceeccf835175a1fd59f24fChris Forbes
60065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6009bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6010bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkComputePipelineCreateInfo *pCreateInfos,
6011bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
60120108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes    bool skip = false;
60135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
60154c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    vector<PIPELINE_STATE *> pPipeState(count);
601656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6019b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
60205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
60215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Verify compute stage bits
60225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Create and initialize internal tracking data structure
60244c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i] = new PIPELINE_STATE;
60254c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i]->initComputePipeline(&pCreateInfos[i]);
6026c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis        pPipeState[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
60275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Add Compute Pipeline Verification
6029e446ad08318228362ef35d73e7a0636075cb3636Chris Forbes        skip |= validate_compute_pipeline(dev_data, pPipeState[i]);
60300108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes        // skip |= verifyPipelineCreateState(dev_data, pPipeState[i]);
60315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60337a456d188475c23b566334be45dc0489b2789653Chris Forbes    if (skip) {
60345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < count; i++) {
60355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Clean up any locally allocated data structures
60364c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis            delete pPipeState[i];
6037fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipelines[i] = VK_NULL_HANDLE;
60385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
60395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
60405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60417a456d188475c23b566334be45dc0489b2789653Chris Forbes
60427a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6043bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6044bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
60457a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
60467a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
6047fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
6048fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            delete pPipeState[i];
6049bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
6050fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipeState[i]->pipeline = pPipelines[i];
6051fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            dev_data->pipelineMap[pPipeState[i]->pipeline] = pPipeState[i];
6052fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        }
60537a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
60547a456d188475c23b566334be45dc0489b2789653Chris Forbes
60555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
605889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
605989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
606056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60614a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSampler(device, pCreateInfo, pAllocator, pSampler);
60625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6063b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6064d31a44af6da568692a73201825459689c9431867Tobin Ehlis        dev_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_STATE>(new SAMPLER_STATE(pSampler, pCreateInfo));
60655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60690c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic bool PreCallValidateCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info) {
6070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.create_descriptor_set_layout) return false;
60710c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    return cvdescriptorset::DescriptorSetLayout::ValidateCreateInfo(dev_data->report_data, create_info);
60720c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
60730c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
60740c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic void PostCallRecordCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info,
60750c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis                                                    VkDescriptorSetLayout set_layout) {
60763f1d2ba6852cf6b1bb4e1f06d690293565108e2cTobin Ehlis    // TODO: Convert this to unique_ptr to avoid leaks
60770c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    dev_data->descriptorSetLayoutMap[set_layout] = new cvdescriptorset::DescriptorSetLayout(create_info, set_layout);
60780c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
60790c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
6080bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
6081bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator,
6082bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VkDescriptorSetLayout *pSetLayout) {
608356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60840c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
60850c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
60860c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    bool skip = PreCallValidateCreateDescriptorSetLayout(dev_data, pCreateInfo);
60870c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    if (!skip) {
60880c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        lock.unlock();
60890c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        result = dev_data->dispatch_table.CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
60900c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        if (VK_SUCCESS == result) {
60910c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            lock.lock();
60920c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            PostCallRecordCreateDescriptorSetLayout(dev_data, pCreateInfo, *pSetLayout);
60930c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        }
60945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60989e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Used by CreatePipelineLayout and CmdPushConstants.
60999e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Note that the index argument is optional and only used by CreatePipelineLayout.
61009e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultzstatic bool validatePushConstantRange(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
61019e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz                                      const char *caller_name, uint32_t index = 0) {
6102cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.push_constant_range) return false;
61039e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    uint32_t const maxPushConstantsSize = dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize;
61043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
61059e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Check that offset + size don't exceed the max.
61069e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Prevent arithetic overflow here by avoiding addition and testing in this order.
61079e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset >= maxPushConstantsSize) || (size > maxPushConstantsSize - offset)) {
61089e24d8153ab63bc3ac08b5a1517c203930b5de91Karl 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.
61099e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6110e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (offset >= maxPushConstantsSize) {
61113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6112315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a0024c, "DS",
61133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with offset %u that "
61143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "exceeds this device's maxPushConstantSize of %u. %s",
6115315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_11a0024c]);
6116e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
6117e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (size > maxPushConstantsSize - offset) {
6118315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6119315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a00254, "DS",
6120315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "%s call has push constants index %u with offset %u and size %u that "
6121315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "exceeds this device's maxPushConstantSize of %u. %s",
6122315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, size, maxPushConstantsSize,
6123315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_11a00254]);
6124e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
61259e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
61264527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (offset >= maxPushConstantsSize) {
61273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6128315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc002e4, "DS",
61293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with offset %u that "
61303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "exceeds this device's maxPushConstantSize of %u. %s",
6131315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_1bc002e4]);
61324527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
61334527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size > maxPushConstantsSize - offset) {
6134315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6135315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc002e6, "DS",
6136315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "%s call has push constants index %u with offset %u and size %u that "
6137315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "exceeds this device's maxPushConstantSize of %u. %s",
6138315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, size, maxPushConstantsSize,
6139315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_1bc002e6]);
61404527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
61419e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
61423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
61433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
61449e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
61459e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
61469e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // size needs to be non-zero and a multiple of 4.
61479e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((size == 0) || ((size & 0x3) != 0)) {
61489e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6149891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size == 0) {
61503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6151315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a00250, "DS",
61523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
61533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be greater than zero. %s",
6154315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_11a00250]);
6155891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
6156891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size & 0x3) {
61573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6158315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a00252, "DS",
61593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
61603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be a multiple of 4. %s",
6161315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_11a00252]);
6162891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
61639e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
61644527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size == 0) {
61653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6166315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc2c21b, "DS",
61673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
61683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be greater than zero. %s",
6169315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_1bc2c21b]);
61704527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
61714527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size & 0x3) {
61723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6173315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc002e2, "DS",
61743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
61753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be a multiple of 4. %s",
6176315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_1bc002e2]);
61774527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
61789e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
61793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
61803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
61819e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
61829e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
61839e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // offset needs to be a multiple of 4.
61849e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset & 0x3) != 0) {
61859e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
61863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6187315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_11a0024e, "DS",
61883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s call has push constants index %u with "
61893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "offset %u. Offset must be a multiple of 4. %s",
6190315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            caller_name, index, offset, validation_error_map[VALIDATION_ERROR_11a0024e]);
61919e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
61923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6193315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_1bc002e0, "DS",
61943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s call has push constants with "
61953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "offset %u. Offset must be a multiple of 4. %s",
6196315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            caller_name, offset, validation_error_map[VALIDATION_ERROR_1bc002e0]);
61979e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
61983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
61993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
62009e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
62015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
62035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6205bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
620689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                    const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
62073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
620856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6209bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // TODO : Add checks for VALIDATION_ERRORS 865-870
62109e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Push Constant Range checks
621107a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    uint32_t i, j;
62125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
62133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validatePushConstantRange(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
62143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                          pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()", i);
62159e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == pCreateInfo->pPushConstantRanges[i].stageFlags) {
62163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6217315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_11a2dc03, "DS", "vkCreatePipelineLayout() call has no stageFlags set. %s",
6218315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_11a2dc03]);
62199e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
62209e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
62213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
622207a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz
6223bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl 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.
622407a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
622507a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz        for (j = i + 1; j < pCreateInfo->pushConstantRangeCount; ++j) {
6226bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz            if (0 != (pCreateInfo->pPushConstantRanges[i].stageFlags & pCreateInfo->pPushConstantRanges[j].stageFlags)) {
62273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6228315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_0fe00248, "DS",
62293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "vkCreatePipelineLayout() Duplicate stage flags found in ranges %d and %d. %s", i, j,
6230315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_0fe00248]);
62319e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz            }
62325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
62335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6234f73b2046273413ea1338dd714d67c39f8e0fa09eChris Forbes
62354a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
62365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6237b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
62385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
623969b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        plNode.layout = *pPipelineLayout;
6240416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.set_layouts.resize(pCreateInfo->setLayoutCount);
62415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
62429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            plNode.set_layouts[i] = GetDescriptorSetLayout(dev_data, pCreateInfo->pSetLayouts[i]);
62435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6244416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.push_constant_ranges.resize(pCreateInfo->pushConstantRangeCount);
62455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
6246416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            plNode.push_constant_ranges[i] = pCreateInfo->pPushConstantRanges[i];
62475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
62485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6252bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
6253bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) {
625456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62554a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
62565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6257a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis        DESCRIPTOR_POOL_STATE *pNewNode = new DESCRIPTOR_POOL_STATE(*pDescriptorPool, pCreateInfo);
62585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (NULL == pNewNode) {
62595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
62609b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(*pDescriptorPool), __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
6261a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                        "Out of memory while attempting to allocate DESCRIPTOR_POOL_STATE in vkCreateDescriptorPool()"))
62625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return VK_ERROR_VALIDATION_FAILED_EXT;
62635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
6264b9e992386a44404152747d66817a733aa127e281Jeremy Hayes            std::lock_guard<std::mutex> lock(global_lock);
62655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
62665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
62675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
62685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Need to do anything if pool create fails?
62695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6273bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
6274bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDescriptorPoolResetFlags flags) {
6275315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    // TODO : Add checks for VALIDATION_ERROR_32a00272
627656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62774a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetDescriptorPool(device, descriptorPool, flags);
62785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6279b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
62805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        clearDescriptorPool(dev_data, device, descriptorPool, flags);
62815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62842c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes// Ensure the pool contains enough descriptors and descriptor sets to satisfy
6285789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// an allocation request. Fills common_data with the total number of descriptors of each type required,
6286789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// as well as DescriptorSetLayout ptrs used for later update.
62877f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlisstatic bool PreCallValidateAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
62887f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                  cvdescriptorset::AllocateDescriptorSetsData *common_data) {
62897a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    // Always update common data
62907a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    cvdescriptorset::UpdateAllocateDescriptorSetsData(dev_data, pAllocateInfo, common_data);
6291cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.allocate_descriptor_sets) return false;
62927e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All state checks for AllocateDescriptorSets is done in single function
62937a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    return cvdescriptorset::ValidateAllocateDescriptorSets(dev_data, pAllocateInfo, common_data);
62947e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis}
62957e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis// Allocation state was good and call down chain was made so update state based on allocating descriptor sets
62967e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlisstatic void PostCallRecordAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
62977f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 VkDescriptorSet *pDescriptorSets,
62987f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 const cvdescriptorset::AllocateDescriptorSetsData *common_data) {
62997e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All the updates are contained in a single cvdescriptorset function
63002c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    cvdescriptorset::PerformAllocateDescriptorSets(pAllocateInfo, pDescriptorSets, common_data, &dev_data->descriptorPoolMap,
6301b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                                                   &dev_data->setMap, dev_data);
63022c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes}
63032c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes
6304bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
6305bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkDescriptorSet *pDescriptorSets) {
630656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6307b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
63087f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    cvdescriptorset::AllocateDescriptorSetsData common_data(pAllocateInfo->descriptorSetCount);
63093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateAllocateDescriptorSets(dev_data, pAllocateInfo, &common_data);
6310b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6311d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
63123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
6313d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
63144a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
63156511ce241f7f210211e0c0e882f3c14889071f4dChris Forbes
63165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6317b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
63187f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis        PostCallRecordAllocateDescriptorSets(dev_data, pAllocateInfo, pDescriptorSets, &common_data);
6319b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
63205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6323cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Verify state before freeing DescriptorSets
6324cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic bool PreCallValidateFreeDescriptorSets(const layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6325cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                              const VkDescriptorSet *descriptor_sets) {
6326cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_descriptor_sets) return false;
63273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
6328cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // First make sure sets being destroyed are not currently in-use
6329405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    for (uint32_t i = 0; i < count; ++i) {
6330405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
63313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateIdleDescriptorSet(dev_data, descriptor_sets[i], "vkFreeDescriptorSets");
6332405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6333405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    }
6334cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
63359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6336a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    if (pool_state && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pool_state->createInfo.flags)) {
6337cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        // Can't Free from a NON_FREE pool
63383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
6339315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pool), __LINE__, VALIDATION_ERROR_28600270, "DS",
63403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
63413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT. %s",
6342315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_28600270]);
6343cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
63443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
6345cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
6346cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Sets have been removed from the pool so update underlying state
6347cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic void PostCallRecordFreeDescriptorSets(layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6348cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                             const VkDescriptorSet *descriptor_sets) {
63499a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6350cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // Update available descriptor sets in pool
6351cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    pool_state->availableSets += count;
6352cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
6353cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // For each freed descriptor add its resources back into the pool as available and remove from pool and setMap
6354cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    for (uint32_t i = 0; i < count; ++i) {
6355405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
6356405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            auto descriptor_set = dev_data->setMap[descriptor_sets[i]];
6357405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            uint32_t type_index = 0, descriptor_count = 0;
6358405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            for (uint32_t j = 0; j < descriptor_set->GetBindingCount(); ++j) {
6359405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                type_index = static_cast<uint32_t>(descriptor_set->GetTypeFromIndex(j));
6360405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                descriptor_count = descriptor_set->GetDescriptorCountFromIndex(j);
6361405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                pool_state->availableDescriptorTypeCount[type_index] += descriptor_count;
6362405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            }
6363405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            freeDescriptorSet(dev_data, descriptor_set);
6364405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            pool_state->sets.erase(descriptor_set);
6365405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6366cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
6367cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
63685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6369bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
6370bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkDescriptorSet *pDescriptorSets) {
637156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
63725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Make sure that no sets being destroyed are in-flight
6373b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
63743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6375b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6376e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
63773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
63784a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
63795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6380b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
6381cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        PostCallRecordFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6382b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
63835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63866b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// TODO : This is a Proof-of-concept for core validation architecture
63876b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  Really we'll want to break out these functions to separate files but
63886b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  keeping it all together here to prove out design
63896b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PreCallValidate* handles validating all of the state prior to calling down chain to UpdateDescriptorSets()
63906b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic bool PreCallValidateUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
63916b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
63926b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkCopyDescriptorSet *pDescriptorCopies) {
6393cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.update_descriptor_sets) return false;
63946b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // First thing to do is perform map look-ups.
63956b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // NOTE : UpdateDescriptorSets is somewhat unique in that it's operating on a number of DescriptorSets
63966b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  so we can't just do a single map look-up up-front, but do them individually in functions below
63976b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis
63986b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Now make call(s) that validate state, but don't perform state updates in this function
63996b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Note, here DescriptorSets is unique in that we don't yet have an instance. Using a helper function in the
64006b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  namespace which will parse params and make calls into specific class instances
6401104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return cvdescriptorset::ValidateUpdateDescriptorSets(dev_data->report_data, dev_data, descriptorWriteCount, pDescriptorWrites,
6402104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis                                                         descriptorCopyCount, pDescriptorCopies);
64036b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
64046b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSets()
64056b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic void PostCallRecordUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
64066b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
64076b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkCopyDescriptorSet *pDescriptorCopies) {
6408104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    cvdescriptorset::PerformUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
64096b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                 pDescriptorCopies);
64106b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
64115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6412bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
6413bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
6414bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkCopyDescriptorSet *pDescriptorCopies) {
64156b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Only map look-up at top level is for device-level layer_data
641656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6417b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
64183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
64193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                    pDescriptorCopies);
6420b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
64213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
64224a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
64234a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                      pDescriptorCopies);
64246b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        lock.lock();
64256b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        // Since UpdateDescriptorSets() is void, nothing to check prior to updating state
64266b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        PostCallRecordUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
64276b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                           pDescriptorCopies);
64285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6431bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo,
6432bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkCommandBuffer *pCommandBuffer) {
643356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
64344a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
64355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6436b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::unique_lock<std::mutex> lock(global_lock);
64379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pPool = GetCommandPoolNode(dev_data, pCreateInfo->commandPool);
6438cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes
6439cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes        if (pPool) {
644072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
64415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to its commandPool map
6442cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes                pPool->commandBuffers.push_back(pCommandBuffer[i]);
64435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
64445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to map
64455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
64465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                resetCB(dev_data, pCommandBuffer[i]);
64475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->createInfo = *pCreateInfo;
64485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->device = device;
64495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
64505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6451b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
64525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
64545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6456883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis// Add bindings between the given cmd buffer & framebuffer and the framebuffer's children
6457c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void AddFramebufferBinding(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, FRAMEBUFFER_STATE *fb_state) {
64589b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    addCommandBufferBinding(&fb_state->cb_bindings, {HandleToUint64(fb_state->framebuffer), kVulkanObjectTypeFramebuffer},
64590245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            cb_state);
6460883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    for (auto attachment : fb_state->attachments) {
6461883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        auto view_state = attachment.view_state;
6462883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (view_state) {
646303ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis            AddCommandBufferBindingImageView(dev_data, cb_state, view_state);
6464883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
64659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto rp_state = GetRenderPassState(dev_data, fb_state->createInfo.renderPass);
6466883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (rp_state) {
64679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            addCommandBufferBinding(&rp_state->cb_bindings, {HandleToUint64(rp_state->renderPass), kVulkanObjectTypeRenderPass},
64689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    cb_state);
6469883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
6470883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    }
6471883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis}
6472883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis
6473bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
64743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
647556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6476b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
64775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate command buffer level
64789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
6479f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
64805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
6481a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        if (cb_node->in_use.load()) {
64823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6483315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00062, "MEM",
648459ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis                            "Calling vkBeginCommandBuffer() on active command buffer %p before it has completed. "
64853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "You must check command buffer fence before this call. %s",
6486315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            commandBuffer, validation_error_map[VALIDATION_ERROR_16e00062]);
64875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6488f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, cb_node);
6489f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
64905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary Command Buffer
64915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
64925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!pInfo) {
64933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
64945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6495315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00066, "DS",
6496bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must have inheritance info. %s", commandBuffer,
6497315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_16e00066]);
64985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
64995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
65002c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->renderPass);
65012c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    string errorString = "";
65029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto framebuffer = GetFramebufferState(dev_data, pInfo->framebuffer);
65032c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    if (framebuffer) {
65042c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        if ((framebuffer->createInfo.renderPass != pInfo->renderPass) &&
65052c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            !verify_renderpass_compatibility(dev_data, framebuffer->renderPassCreateInfo.ptr(),
65069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                             GetRenderPassState(dev_data, pInfo->renderPass)->createInfo.ptr(),
65072c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                             errorString)) {
65082c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            // renderPass that framebuffer was created with must be compatible with local renderPass
65093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
65109b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
6511315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                            VALIDATION_ERROR_0280006e, "DS",
65123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "vkBeginCommandBuffer(): Secondary Command "
65133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "Buffer (0x%p) renderPass (0x%" PRIxLEAST64
65143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            ") is incompatible w/ framebuffer "
65153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "(0x%" PRIxLEAST64 ") w/ render pass (0x%" PRIxLEAST64 ") due to: %s. %s",
65169b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                            commandBuffer, HandleToUint64(pInfo->renderPass), HandleToUint64(pInfo->framebuffer),
65179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                            HandleToUint64(framebuffer->createInfo.renderPass), errorString.c_str(),
6518315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                            validation_error_map[VALIDATION_ERROR_0280006e]);
65195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
65202c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        // Connect this framebuffer and its children to this cmdBuffer
65212c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        AddFramebufferBinding(dev_data, cb_node, framebuffer);
65225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
65235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
65244527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                if ((pInfo->occlusionQueryEnable == VK_FALSE || dev_data->enabled_features.occlusionQueryPrecise == VK_FALSE) &&
65255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
65263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
65279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
6528315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    VALIDATION_ERROR_16e00068, "DS",
65293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must not have "
65303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not "
65313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "support precise occlusion queries. %s",
6532315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    commandBuffer, validation_error_map[VALIDATION_ERROR_16e00068]);
65335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
65345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
65355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
65369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto renderPass = GetRenderPassState(dev_data, pInfo->renderPass);
653716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                if (renderPass) {
6538fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    if (pInfo->subpass >= renderPass->createInfo.subpassCount) {
65393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
65409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
6541315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        VALIDATION_ERROR_0280006c, "DS",
65423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        "vkBeginCommandBuffer(): Secondary Command Buffers (0x%p) must have a subpass index (%d) "
65433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        "that is less than the number of subpasses (%d). %s",
65443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        commandBuffer, pInfo->subpass, renderPass->createInfo.subpassCount,
6545315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        validation_error_map[VALIDATION_ERROR_0280006c]);
65465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
65475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
65485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
65495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6550f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (CB_RECORDING == cb_node->state) {
65513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6552315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00062, "DS",
65533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkBeginCommandBuffer(): Cannot call Begin on command buffer (0x%p"
65543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") in the RECORDING state. Must first call vkEndCommandBuffer(). %s",
6555315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            commandBuffer, validation_error_map[VALIDATION_ERROR_16e00062]);
6556347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        } else if (CB_RECORDED == cb_node->state || (CB_INVALID == cb_node->state && CMD_END == cb_node->last_cmd)) {
6557f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            VkCommandPool cmdPool = cb_node->createInfo.commandPool;
65589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pPool = GetCommandPoolNode(dev_data, cmdPool);
6559cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes            if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
65603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
65615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6562315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00064, "DS",
6563226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "Call to vkBeginCommandBuffer() on command buffer (0x%p"
6564414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") attempts to implicitly reset cmdBuffer created from command pool (0x%" PRIxLEAST64
65654527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
6566315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            commandBuffer, HandleToUint64(cmdPool), validation_error_map[VALIDATION_ERROR_16e00064]);
65675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
65685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            resetCB(dev_data, commandBuffer);
65695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
65705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Set updated state here in case implicit reset occurs above
6571f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->state = CB_RECORDING;
6572f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->beginInfo = *pBeginInfo;
6573f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->beginInfo.pInheritanceInfo) {
6574f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->inheritanceInfo = *(cb_node->beginInfo.pInheritanceInfo);
6575f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->beginInfo.pInheritanceInfo = &cb_node->inheritanceInfo;
6576888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            // If we are a secondary command-buffer and inheriting.  Update the items we should inherit.
6577f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) &&
6578f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                (cb_node->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
65799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                cb_node->activeRenderPass = GetRenderPassState(dev_data, cb_node->beginInfo.pInheritanceInfo->renderPass);
6580f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->activeSubpass = cb_node->beginInfo.pInheritanceInfo->subpass;
6581350841afb70bf8dcfc3c6ec6b66f0aaa639553a3Tobin Ehlis                cb_node->activeFramebuffer = cb_node->beginInfo.pInheritanceInfo->framebuffer;
6582f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->framebuffers.insert(cb_node->beginInfo.pInheritanceInfo->framebuffer);
6583888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            }
65845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
65855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6586b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
65873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
65885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
65895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65904a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.BeginCommandBuffer(commandBuffer, pBeginInfo);
6591400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
65925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
65935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
659589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL EndCommandBuffer(VkCommandBuffer commandBuffer) {
65963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
659756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6598b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
65999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
66005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
66014527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        if ((VK_COMMAND_BUFFER_LEVEL_PRIMARY == pCB->createInfo.level) ||
66024527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
6603fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // This needs spec clarification to update valid usage, see comments in PR:
6604fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/pull/516#discussion_r63013756
6605315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= insideRenderPass(dev_data, pCB, "vkEndCommandBuffer()", VALIDATION_ERROR_27400078);
6606fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop        }
66073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_END, "vkEndCommandBuffer()");
66081ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_END);
66095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto query : pCB->activeQueries) {
66103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6611315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_2740007a, "DS",
66123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Ending command buffer with in progress query: queryPool 0x%" PRIx64 ", index %d. %s",
6613315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(query.pool), query.index, validation_error_map[VALIDATION_ERROR_2740007a]);
66145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
66155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
6617b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
66180d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        auto result = dev_data->dispatch_table.EndCommandBuffer(commandBuffer);
6619b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
66205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (VK_SUCCESS == result) {
66215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->state = CB_RECORDED;
66225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
66230d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        return result;
66245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
66250d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
66265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6629bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
66303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
663156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6632b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
66339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
66345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkCommandPool cmdPool = pCB->createInfo.commandPool;
66359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, cmdPool);
6636cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes    if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
66373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6638315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_3260005c, "DS",
66393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Attempt to reset command buffer (0x%p) created from command pool (0x%" PRIxLEAST64
66403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
6641315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        commandBuffer, HandleToUint64(cmdPool), validation_error_map[VALIDATION_ERROR_3260005c]);
66425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6643315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= checkCommandBufferInFlight(dev_data, pCB, "reset", VALIDATION_ERROR_3260005a);
6644b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
66453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
66464a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandBuffer(commandBuffer, flags);
66475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6648b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
66495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        resetCB(dev_data, commandBuffer);
6650b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
66515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
665493c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
6655bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
6656bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkPipeline pipeline) {
6657e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    bool skip = false;
665856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6659b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
66609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
6661e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    if (cb_state) {
6662baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindPipeline()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6663315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_18002415);
666429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
66651ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_state, CMD_BINDPIPELINE);
6666e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (cb_state->activeRenderPass)) {
6667e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |=
66685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
66699b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pipeline), __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
6670414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "Incorrectly binding compute pipeline (0x%" PRIxLEAST64 ") during active RenderPass (0x%" PRIxLEAST64 ")",
66719b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pipeline), HandleToUint64(cb_state->activeRenderPass->renderPass));
66725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6673315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        // TODO: VALIDATION_ERROR_18000612 VALIDATION_ERROR_18000616
66745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6675e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        PIPELINE_STATE *pipe_state = getPipelineState(dev_data, pipeline);
6676e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (pipe_state) {
6677e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            cb_state->lastBound[pipelineBindPoint].pipeline_state = pipe_state;
6678e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_cb_pso_status(cb_state, pipe_state);
6679e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_pipeline_state(pipe_state);
6680daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            skip |= validate_dual_src_blend_feature(dev_data, pipe_state);
66815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
6682e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
6683315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pipeline), __LINE__, VALIDATION_ERROR_18027e01, "DS",
66849b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Attempt to bind Pipeline 0x%" PRIxLEAST64 " that doesn't exist! %s", HandleToUint64(pipeline),
6685315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_18027e01]);
6686e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        }
66879b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        addCommandBufferBinding(&pipe_state->cb_bindings, {HandleToUint64(pipeline), kVulkanObjectTypePipeline}, cb_state);
6688e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
6689e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            // Add binding for child renderpass
66909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto rp_state = GetRenderPassState(dev_data, pipe_state->graphicsPipelineCI.renderPass);
6691e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            if (rp_state) {
66929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                addCommandBufferBinding(&rp_state->cb_bindings, {HandleToUint64(rp_state->renderPass), kVulkanObjectTypeRenderPass},
66939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        cb_state);
6694e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            }
66955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
66965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6697b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6698cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
66995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6701bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
6702bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          const VkViewport *pViewports) {
67033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
670456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6705b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6708315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetViewport()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1e002415);
67093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()");
67101ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETVIEWPORTSTATE);
6711bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->viewportMask |= ((1u << viewportCount) - 1u) << firstViewport;
67125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6713b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
67155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6717bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
6718bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         const VkRect2D *pScissors) {
67193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
672056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6721b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6724315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetScissor()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1d802415);
67253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()");
67261ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSCISSORSTATE);
6727bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->scissorMask |= ((1u << scissorCount) - 1u) << firstScissor;
67285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6729b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
67315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
673389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
67343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
673556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6736b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6739315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetLineWidth()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1d602415);
67403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()");
67411ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETLINEWIDTHSTATE);
67425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_LINE_WIDTH_SET;
6743a27508babf63d50aea75883a3702979193c23683Mark Young
67444c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pPipeTrav = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline_state;
6745a27508babf63d50aea75883a3702979193c23683Mark Young        if (pPipeTrav != NULL && !isDynamic(pPipeTrav, VK_DYNAMIC_STATE_LINE_WIDTH)) {
67463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6747315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1d600626, "DS",
67483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdSetLineWidth called but pipeline was created without VK_DYNAMIC_STATE_LINE_WIDTH "
67493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "flag.  This is undefined behavior and could be ignored. %s",
6750315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1d600626]);
6751a27508babf63d50aea75883a3702979193c23683Mark Young        } else {
67529b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_SET, kVulkanObjectTypeCommandBuffer, HandleToUint64(commandBuffer),
67539b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    lineWidth);
6754a27508babf63d50aea75883a3702979193c23683Mark Young        }
67555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6756b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetLineWidth(commandBuffer, lineWidth);
67585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6760bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
6761bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           float depthBiasSlopeFactor) {
67623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
676356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6764b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6767315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetDepthBias()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1cc02415);
67683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()");
6769434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        if ((depthBiasClamp != 0.0) && (!dev_data->enabled_features.depthBiasClamp)) {
67703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6771315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1cc0062c, "DS",
67723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdSetDepthBias(): the depthBiasClamp device feature is disabled: the depthBiasClamp "
67733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "parameter must be set to 0.0. %s",
6774315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1cc0062c]);
6775434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
67763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        if (!skip) {
6777434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBIASSTATE);
6778434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            pCB->status |= CBSTATUS_DEPTH_BIAS_SET;
6779434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
67805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6781b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip)
67834a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
67845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
678689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
67873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
678856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6789b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6792315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetBlendConstants()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1ca02415);
67933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()");
67941ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETBLENDSTATE);
67953d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        pCB->status |= CBSTATUS_BLEND_CONSTANTS_SET;
67965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6797b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetBlendConstants(commandBuffer, blendConstants);
67995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6801bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
68023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
680356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6804b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6807315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetDepthBounds()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1ce02415);
68083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()");
68091ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBOUNDSSTATE);
68105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET;
68115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6812b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
68133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
68145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6816bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
6817bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    uint32_t compareMask) {
68183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
681956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6820b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6823315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
6824315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilCompareMask()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1da02415);
68253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()");
68261ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREADMASKSTATE);
68275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET;
68285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6829b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
68303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
68315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6833bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
68343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
683556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6836b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6839315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
6840315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilWriteMask()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1de02415);
68413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()");
68421ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILWRITEMASKSTATE);
68435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
68445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6845b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
68463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
68475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6849bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
68503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
685156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6852b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6855315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
6856315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilReference()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1dc02415);
68573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()");
68581ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREFERENCESTATE);
68595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET;
68605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6861b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
68623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilReference(commandBuffer, faceMask, reference);
68635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6865bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
6866bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
6867bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
6868bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const uint32_t *pDynamicOffsets) {
6869946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
687056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6871b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6872946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
6873946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
6874baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindDescriptorSets()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6875315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_17c02415);
6876946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()");
6877ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        // Track total count of dynamic descriptor types to make sure we have an offset for each one
6878946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t total_dynamic_descriptors = 0;
6879946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        string error_string = "";
6880946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t last_set_index = firstSet + setCount - 1;
6881946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (last_set_index >= cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size()) {
6882946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
6883946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].dynamicOffsets.resize(last_set_index + 1);
6884946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        }
6885946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        auto old_final_bound_set = cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index];
6886ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        auto pipeline_layout = getPipelineLayout(dev_data, layout);
6887ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t set_idx = 0; set_idx < setCount; set_idx++) {
6888ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cvdescriptorset::DescriptorSet *descriptor_set = GetSetNode(dev_data, pDescriptorSets[set_idx]);
6889ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (descriptor_set) {
6890946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].pipeline_layout = *pipeline_layout;
6891946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[set_idx + firstSet] = descriptor_set;
6892946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
68939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(pDescriptorSets[set_idx]), __LINE__,
6894946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                DRAWSTATE_NONE, "DS", "Descriptor Set 0x%" PRIxLEAST64 " bound on pipeline %s",
68959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pDescriptorSets[set_idx]), string_VkPipelineBindPoint(pipelineBindPoint));
6896ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                if (!descriptor_set->IsUpdated() && (descriptor_set->GetTotalDescriptorCount() != 0)) {
6897946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
68989b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(pDescriptorSets[set_idx]),
68999b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
6900946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "Descriptor Set 0x%" PRIxLEAST64
6901946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    " bound but it was never updated. You may want to either update it or not bind it.",
69029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(pDescriptorSets[set_idx]));
6903ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
6904ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
690512b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                if (!verify_set_layout_compatibility(descriptor_set, pipeline_layout, set_idx + firstSet, error_string)) {
6906946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
69079b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(pDescriptorSets[set_idx]),
6908315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    __LINE__, VALIDATION_ERROR_17c002cc, "DS",
6909946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout "
6910946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "at index %u of pipelineLayout 0x%" PRIxLEAST64 " due to: %s. %s",
69119b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    set_idx, set_idx + firstSet, HandleToUint64(layout), error_string.c_str(),
6912315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_17c002cc]);
69135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
6914ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
6915946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                auto set_dynamic_descriptor_count = descriptor_set->GetDynamicDescriptorCount();
6916ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
6917946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx].clear();
6918ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
6919946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (set_dynamic_descriptor_count) {
6920ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    // First make sure we won't overstep bounds of pDynamicOffsets array
6921946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if ((total_dynamic_descriptors + set_dynamic_descriptor_count) > dynamicOffsetCount) {
69229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        skip |= log_msg(
69239b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
69249b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pDescriptorSets[set_idx]), __LINE__, DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
69259b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "descriptorSet #%u (0x%" PRIxLEAST64
69269b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
69279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "array. There must be one dynamic offset for each dynamic descriptor being bound.",
69289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            set_idx, HandleToUint64(pDescriptorSets[set_idx]), descriptor_set->GetDynamicDescriptorCount(),
69299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            (dynamicOffsetCount - total_dynamic_descriptors));
6930ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    } else {  // Validate and store dynamic offsets with the set
6931ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Validate Dynamic Offset Minimums
6932946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        uint32_t cur_dyn_offset = total_dynamic_descriptors;
6933ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        for (uint32_t d = 0; d < descriptor_set->GetTotalDescriptorCount(); d++) {
6934ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
693516769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                                if (SafeModulo(
6936ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
6937ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
6938315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    skip |=
6939315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
6940315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
6941315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VALIDATION_ERROR_17c002d4, "DS",
6942315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
6943315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
6944315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
6945315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
6946315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                validation_error_map[VALIDATION_ERROR_17c002d4]);
6947ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
6948ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
6949ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            } else if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
695016769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                                if (SafeModulo(
6951ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
6952ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
6953315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    skip |=
6954315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
6955315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
6956315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VALIDATION_ERROR_17c002d4, "DS",
6957315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
6958315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
6959315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
6960315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment,
6961315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                validation_error_map[VALIDATION_ERROR_17c002d4]);
6962ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
6963ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
6964ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            }
696572d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        }
6966ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
6967946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx] =
6968946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            std::vector<uint32_t>(pDynamicOffsets + total_dynamic_descriptors,
6969946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                  pDynamicOffsets + total_dynamic_descriptors + set_dynamic_descriptor_count);
6970ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Keep running total of dynamic descriptor count to verify at the end
6971946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        total_dynamic_descriptors += set_dynamic_descriptor_count;
697272d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    }
697372d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                }
6974ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            } else {
69759b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |=
69769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
69779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pDescriptorSets[set_idx]), __LINE__, DRAWSTATE_INVALID_SET, "DS",
69789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Attempt to bind descriptor set 0x%" PRIxLEAST64 " that doesn't exist!",
69799b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pDescriptorSets[set_idx]));
6980ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            }
6981946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            UpdateCmdBufferLastCmd(cb_state, CMD_BINDDESCRIPTORSETS);
6982ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update
6983ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (firstSet > 0) {  // Check set #s below the first bound set
6984ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                for (uint32_t i = 0; i < firstSet; ++i) {
6985946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if (cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] &&
698612b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                        !verify_set_layout_compatibility(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i],
6987946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                         pipeline_layout, i, error_string)) {
6988946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        skip |= log_msg(
6989ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
6990ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
69919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i]), __LINE__, DRAWSTATE_NONE,
69929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "DS", "DescriptorSet 0x%" PRIxLEAST64
69939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                  " previously bound as set #%u was disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
69949b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i]), i,
69959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(layout));
6996946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE;
69975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
69985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
69995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7000ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // Check if newly last bound set invalidates any remaining bound sets
7001946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            if ((cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (last_set_index)) {
7002946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (old_final_bound_set &&
700312b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                    !verify_set_layout_compatibility(old_final_bound_set, pipeline_layout, last_set_index, error_string)) {
7004946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    auto old_set = old_final_bound_set->GetSet();
7005946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
70069b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(old_set), __LINE__,
7007946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    DRAWSTATE_NONE, "DS", "DescriptorSet 0x%" PRIxLEAST64
7008946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " previously bound as set #%u is incompatible with set 0x%" PRIxLEAST64
7009946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " newly bound as set #%u so set #%u and any subsequent sets were "
7010946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          "disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
70119b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(old_set), last_set_index,
70129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index]),
70139b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    last_set_index, last_set_index + 1, HandleToUint64(layout));
7014946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
7015ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
7016787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            }
7017ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
7018ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
7019946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (total_dynamic_descriptors != dynamicOffsetCount) {
7020315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |=
7021315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7022315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_17c002ce, "DS",
7023315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
7024315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "is %u. It should exactly match the number of dynamic descriptors. %s",
7025315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        setCount, total_dynamic_descriptors, dynamicOffsetCount, validation_error_map[VALIDATION_ERROR_17c002ce]);
70265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
70275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7028b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7029946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
70304a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
70314a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                       pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
70325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7034bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7035bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkIndexType indexType) {
7036946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
703756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7038593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that IBs have correct usage state flagged
7039b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7040b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
70419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
70429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
70435cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && buffer_state) {
7044315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
7045315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBindIndexBuffer()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_17e02415);
7046946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
7047315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindIndexBuffer()", VALIDATION_ERROR_17e00364);
7048ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        std::function<bool()> function = [=]() {
7049ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindIndexBuffer()");
7050ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        };
7051ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->validate_functions.push_back(function);
7052ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDINDEXBUFFER);
7053ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        VkDeviceSize offset_align = 0;
7054ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        switch (indexType) {
7055ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT16:
7056ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 2;
7057ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
7058ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT32:
7059ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 4;
7060ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
7061ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            default:
7062ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0
7063ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
70645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7065ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        if (!offset_align || (offset % offset_align)) {
7066df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
70679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(commandBuffer), __LINE__, DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS",
7068946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") does not fall on alignment (%s) boundary.", offset,
7069946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            string_VkIndexType(indexType));
7070ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
7071ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->status |= CBSTATUS_INDEX_BUFFER_BOUND;
7072ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7073ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
70745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7075b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7076946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
70775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
70795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisvoid updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) {
70805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t end = firstBinding + bindingCount;
70815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->currentDrawData.buffers.size() < end) {
70825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.resize(end);
70835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bindingCount; ++i) {
70855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i];
70865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7089e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic inline void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); }
70905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7091bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
7092bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
7093946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
709456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7095593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that VBs have correct usage state flagged
7096b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7097b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
70989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
70999f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    if (cb_node) {
7100315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
7101315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBindVertexBuffers()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_18202415);
7102baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffers()");
7103ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t i = 0; i < bindingCount; ++i) {
7104ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            auto buffer_state = GetBufferState(dev_data, pBuffers[i]);
7105ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            assert(buffer_state);
7106315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindVertexBuffers()", VALIDATION_ERROR_182004e8);
7107ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            std::function<bool()> function = [=]() {
7108ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindVertexBuffers()");
7109ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            };
7110ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cb_node->validate_functions.push_back(function);
71115fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour            if (pOffsets[i] >= buffer_state->createInfo.size) {
71125fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
7113315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(buffer_state->buffer), __LINE__, VALIDATION_ERROR_182004e4, "DS",
71145fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour                                "vkCmdBindVertexBuffers() offset (0x%" PRIxLEAST64 ") is beyond the end of the buffer. %s",
7115315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                pOffsets[i], validation_error_map[VALIDATION_ERROR_182004e4]);
71165fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour            }
71175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7118ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDVERTEXBUFFER);
7119ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        updateResourceTracking(cb_node, firstBinding, bindingCount, pBuffers);
71205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
71217828015969ab31ee01d597f0288cbb124b637fcdMark Lobodzinski        assert(0);
71225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7123b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7124946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
71255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
712725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Expects global_lock to be held by caller
71285569d6457ac22e7d245f3cdee045e71ffbc8b06eTobin Ehlisstatic void MarkStoreImagesAndBuffersAsWritten(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
71297a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto imageView : pCB->updateImages) {
71309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, imageView);
7131cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!view_state) continue;
7132249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
71339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, view_state->create_info.image);
71341facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        assert(image_state);
7135e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
71361facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, image_state, true);
7137e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
71387a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
71397a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
71407a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    }
71417a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto buffer : pCB->updateBuffers) {
71429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, buffer);
71435cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        assert(buffer_state);
7144e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
71455cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, buffer_state, true);
7146e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
71477a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
71487a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
71495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
71505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7152ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle validation for all CmdDraw* type functions
7153ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool ValidateCmdDrawType(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7154baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                CMD_TYPE cmd_type, GLOBAL_CB_NODE **cb_state, const char *caller, VkQueueFlags queue_flags,
7155baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                UNIQUE_VALIDATION_ERROR_CODE queue_flag_code, UNIQUE_VALIDATION_ERROR_CODE msg_code,
7156baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                UNIQUE_VALIDATION_ERROR_CODE const dynamic_state_msg_code) {
715758b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    bool skip = false;
71589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cb_state = GetCBNode(dev_data, cmd_buffer);
715958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (*cb_state) {
7160baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, *cb_state, caller, queue_flags, queue_flag_code);
7161ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        skip |= ValidateCmd(dev_data, *cb_state, cmd_type, caller);
71624f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        skip |= ValidateDrawState(dev_data, *cb_state, indexed, bind_point, caller, dynamic_state_msg_code);
716325d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        skip |= (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) ? outsideRenderPass(dev_data, *cb_state, caller, msg_code)
716425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis                                                                : insideRenderPass(dev_data, *cb_state, caller, msg_code);
716558b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
716658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    return skip;
716758b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis}
716858b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis
716925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis// Generic function to handle state update for all CmdDraw* and CmdDispatch* type functions
7170ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawDispatchType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7171ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           CMD_TYPE cmd_type) {
7172ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateDrawState(dev_data, cb_state, bind_point);
71732f921d33544c162dcb726fc3c7b915e89c02ff24Tobin Ehlis    MarkStoreImagesAndBuffersAsWritten(dev_data, cb_state);
71741ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis    UpdateCmdBufferLastCmd(cb_state, cmd_type);
717525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
717625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7177ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle state update for all CmdDraw* type functions
7178ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7179b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes                                   CMD_TYPE cmd_type) {
7180ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, cmd_type);
7181c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    updateResourceTrackingOnDraw(cb_state);
7182b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    cb_state->hasDrawCmd = true;
7183ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7184ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7185ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDraw(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7186ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   GLOBAL_CB_NODE **cb_state, const char *caller) {
7187baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAW, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
7188315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               VALIDATION_ERROR_1a202415, VALIDATION_ERROR_1a200017, VALIDATION_ERROR_1a200376);
7189ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7190ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7191ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDraw(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7192b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAW);
7193c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis}
7194c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis
719589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
719689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                   uint32_t firstVertex, uint32_t firstInstance) {
719756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
719858b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7199b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7200ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = PreCallValidateCmdDraw(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state, "vkCmdDraw()");
7201b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
720258b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (!skip) {
72034a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
7204c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.lock();
7205ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDraw(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7206c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.unlock();
7207c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    }
72085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7210ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexed(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7211ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
7212baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXED, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
7213315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               VALIDATION_ERROR_1a402415, VALIDATION_ERROR_1a400017, VALIDATION_ERROR_1a40039c);
7214ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7215ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7216ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexed(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7217b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXED);
7218ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7219ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7220bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
7221bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
722256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7223ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7224b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7225ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexed(dev_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7226ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              "vkCmdDrawIndexed()");
7227b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7228ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    if (!skip) {
72294a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
7230ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.lock();
7231ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexed(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7232ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.unlock();
7233ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    }
72345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7236ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7237ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
7238ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           const char *caller) {
7239315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    bool skip =
7240315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDIRECT, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
7241315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            VALIDATION_ERROR_1aa02415, VALIDATION_ERROR_1aa00017, VALIDATION_ERROR_1aa003cc);
72429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
7243315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_1aa003b4);
724413c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
724513c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // VkDrawIndirectCommand structures accessed by this command must be 0, which will require access to the contents of 'buffer'.
7246d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    return skip;
7247d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7248d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7249ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7250ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          BUFFER_STATE *buffer_state) {
7251b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDIRECT);
7252d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
7253d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7254d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7255bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
7256bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           uint32_t stride) {
725756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7258d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7259d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7260b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7261872a2f0ca3ffdeddfa7483e777191fa64b853892Tony Barbour    bool skip = PreCallValidateCmdDrawIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7262ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               &buffer_state, "vkCmdDrawIndirect()");
7263b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7264d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    if (!skip) {
72654a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
7266d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.lock();
7267ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
7268d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.unlock();
7269d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    }
72705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7272ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexedIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7273ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7274ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  BUFFER_STATE **buffer_state, const char *caller) {
7275315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    bool skip =
7276315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXEDINDIRECT, cb_state, caller,
7277315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1a602415, VALIDATION_ERROR_1a600017, VALIDATION_ERROR_1a600434);
72789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
7279315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_1a60041c);
728013c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
728113c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // VkDrawIndexedIndirectCommand structures accessed by this command must be 0, which will require access to the contents of
728213c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // 'buffer'.
72830c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    return skip;
72840c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
72850c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7286ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexedIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7287ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                 BUFFER_STATE *buffer_state) {
7288b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXEDINDIRECT);
72890c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
72900c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
72910c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7292bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7293bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  uint32_t count, uint32_t stride) {
729456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
72950c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
72960c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7297b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
72980c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexedIndirect(dev_data, commandBuffer, buffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS,
7299ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                      &cb_state, &buffer_state, "vkCmdDrawIndexedIndirect()");
7300b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
73010c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    if (!skip) {
73024a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
73030c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.lock();
7304ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexedIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
73050c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.unlock();
73060c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    }
73075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7309ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatch(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7310ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                       VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
7311baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCH, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
7312315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               VALIDATION_ERROR_19c02415, VALIDATION_ERROR_19c00017, VALIDATION_ERROR_UNDEFINED);
731325d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
731425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7315ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatch(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7316ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCH);
731725d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
731825d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
731989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
732056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
732125d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7322b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7323ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip =
7324ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PreCallValidateCmdDispatch(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_COMPUTE, &cb_state, "vkCmdDispatch()");
7325b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
732625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    if (!skip) {
73274a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatch(commandBuffer, x, y, z);
732825d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.lock();
7329ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatch(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
733025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.unlock();
733125d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    }
73325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7334ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatchIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7335ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7336ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               BUFFER_STATE **buffer_state, const char *caller) {
7337baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    bool skip =
7338baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCHINDIRECT, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
7339315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            VALIDATION_ERROR_1a002415, VALIDATION_ERROR_1a000017, VALIDATION_ERROR_UNDEFINED);
73409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
7341315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_1a000322);
734279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    return skip;
734379c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
734479c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7345ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatchIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7346ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              BUFFER_STATE *buffer_state) {
7347ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCHINDIRECT);
734879c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
734979c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
735079c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7351bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
735256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
735379c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
735479c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7355b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
73567433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis    bool skip = PreCallValidateCmdDispatchIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_COMPUTE,
7357ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                   &cb_state, &buffer_state, "vkCmdDispatchIndirect()");
7358b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
735979c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    if (!skip) {
73604a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatchIndirect(commandBuffer, buffer, offset);
736179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.lock();
7362ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatchIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, buffer_state);
736379c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.unlock();
736479c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    }
73655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
736789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
736889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                         uint32_t regionCount, const VkBufferCopy *pRegions) {
7369c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7370b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7371ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
7372c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7373c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
7374c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
7375593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7376c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    if (cb_node && src_buffer_state && dst_buffer_state) {
7377c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        bool skip = PreCallValidateCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7378c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        if (!skip) {
7379c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            PreCallRecordCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7380c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            lock.unlock();
7381c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            device_data->dispatch_table.CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
7382c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        }
7383ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7384c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        lock.unlock();
7385ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
73865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
73875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7389bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7390bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7391bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageCopy *pRegions) {
73926a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    bool skip = false;
73936a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7394b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7395249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
73966a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
73976a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
73986a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
73991facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && src_image_state && dst_image_state) {
74006a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        skip = PreCallValidateCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions,
74016a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                           srcImageLayout, dstImageLayout);
74026a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        if (!skip) {
7403a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis            PreCallRecordCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, srcImageLayout,
7404a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                      dstImageLayout);
74056a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            lock.unlock();
74066a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            device_data->dispatch_table.CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
74076a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                                     pRegions);
74085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7409249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
74106a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        lock.unlock();
7411249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
74125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
74135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7415eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski// Validate that an image's sampleCount matches the requirement for a specific API call
741660568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageSampleCount(layer_data *dev_data, IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count,
741760568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinski                              const char *location, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
7418eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    bool skip = false;
74191facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state->createInfo.samples != sample_count) {
74209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
74219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(image_state->image), 0, msgCode, "DS",
74229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       "%s for image 0x%" PRIxLEAST64 " was created with a sample count of %s but must be %s. %s", location,
74239b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(image_state->image), string_VkSampleCountFlagBits(image_state->createInfo.samples),
74249b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       string_VkSampleCountFlagBits(sample_count), validation_error_map[msgCode]);
7425eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    }
7426eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    return skip;
7427eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski}
7428eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski
7429bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7430bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7431bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageBlit *pRegions, VkFilter filter) {
743256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7433b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7434593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
74359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
74369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
74379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
74380dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7439055112ec99304db71d55b69a60e1da14e8af8f60Mark Lobodzinski    bool skip = PreCallValidateCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, filter);
74400dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7441dca02371c9531e7a9a2a51decae1db4d297862c4Mark Lobodzinski    if (!skip) {
7442eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        PreCallRecordCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state);
7443eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        lock.unlock();
74444a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
74454a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                              pRegions, filter);
74460dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski    }
74475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7449bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
7450bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkImageLayout dstImageLayout, uint32_t regionCount,
7451bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBufferImageCopy *pRegions) {
7452940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7453b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7454940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
7455940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7456940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
7457940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
7458940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_buffer_state && dst_image_state) {
7459940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyBufferToImage(device_data, dstImageLayout, cb_node, src_buffer_state, dst_image_state,
746071c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyBufferToImage()");
7461ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7462d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7463ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
7464e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01244 here, or put in object tracker?
74655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7466940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
7467a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis        PreCallRecordCmdCopyBufferToImage(device_data, cb_node, src_buffer_state, dst_image_state, regionCount, pRegions,
7468a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                          dstImageLayout);
7469d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7470940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
7471d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
74725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7474bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7475bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
7476940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
7477940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7478b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7479593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7480940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7481940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
7482940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
7483940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_image_state && dst_buffer_state) {
7484940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyImageToBuffer(device_data, srcImageLayout, cb_node, src_image_state, dst_buffer_state,
748571c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyImageToBuffer()");
7486ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7487d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7488ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
7489e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01262 here, or put in object tracker?
74905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7491940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
7492a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis        PreCallRecordCmdCopyImageToBuffer(device_data, cb_node, src_image_state, dst_buffer_state, regionCount, pRegions,
7493a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                          srcImageLayout);
7494d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7495940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
7496d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
74975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7499bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7500bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkDeviceSize dataSize, const uint32_t *pData) {
75013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
750256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7503b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7504593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
75059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
75069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
75075cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
7508315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdUpdateBuffer()", VALIDATION_ERROR_1e400046);
7509ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
75105cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
7511ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
7512315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
7513315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                         VALIDATION_ERROR_1e400044, "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
7514e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
75155cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
7516e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
75175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
75189f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
7519593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7520315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
7521315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdUpdateBuffer()",
7522315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_1e402415);
75233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()");
75241ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_node, CMD_UPDATEBUFFER);
7525315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, cb_node, "vkCmdUpdateBuffer()", VALIDATION_ERROR_1e400017);
7526ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7527ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
75285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7529b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
75303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
75315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7533bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7534bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         VkDeviceSize size, uint32_t data) {
753523bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7536b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
753723bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
753823bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto buffer_state = GetBufferState(device_data, dstBuffer);
7539593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
754023bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    if (cb_node && buffer_state) {
754123bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        bool skip = PreCallValidateCmdFillBuffer(device_data, cb_node, buffer_state);
754223bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        if (!skip) {
754323bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            PreCallRecordCmdFillBuffer(device_data, cb_node, buffer_state);
754423bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            lock.unlock();
754523bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            device_data->dispatch_table.CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
754623bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        }
7547ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
754823bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        lock.unlock();
7549ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
75505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
75515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
75534028af23e688ab5730f48ab2244dd042e2eefaedMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
75544028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearAttachment *pAttachments, uint32_t rectCount,
75554028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearRect *pRects) {
75564028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    bool skip = false;
755756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
75584028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    {
75594028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
75604028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        skip = PreCallValidateCmdClearAttachments(dev_data, commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
75614028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    }
7562cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
75635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
75650482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
75660482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkClearColorValue *pColor, uint32_t rangeCount,
75670482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkImageSubresourceRange *pRanges) {
756856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7569b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75700482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
75710482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearColorImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
75720482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
75730482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARCOLORIMAGE);
75740482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
75750482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
75760482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    }
75770482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski}
75780482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
75790482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
75800482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
75810482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkImageSubresourceRange *pRanges) {
758256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
75830482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
75840482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
75850482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearDepthStencilImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
75860482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
75870482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARDEPTHSTENCILIMAGE);
75880482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
75890482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
75907f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    }
75915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7593bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7594bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7595bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkImageResolve *pRegions) {
759656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7597b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7598593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
75999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
76009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
76019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
760209fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
760325f7873c9ce3ed39d18bba8750d7538905e150dfMark Lobodzinski    bool skip = PreCallValidateCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions);
760409fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
760509fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    if (!skip) {
76066c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        PreCallRecordCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state);
76076c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        lock.unlock();
76084a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
76094a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                 pRegions);
761009fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    }
76115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7613a8d1e377bdeaf61a3209cb997502da4356a185bbMike WeiblenVKAPI_ATTR void VKAPI_CALL GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
7614a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen                                                     VkSubresourceLayout *pLayout) {
7615a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
7616a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen
7617a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    bool skip = PreCallValidateGetImageSubresourceLayout(device_data, image, pSubresource);
7618a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    if (!skip) {
7619b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        device_data->dispatch_table.GetImageSubresourceLayout(device, image, pSubresource, pLayout);
7620b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    }
7621b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski}
7622b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski
7623b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentinebool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
762456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
76259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
7626b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (pCB) {
7627b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventToStageMap[event] = stageMask;
7628b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7629b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    auto queue_data = dev_data->queueMap.find(queue);
7630b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (queue_data != dev_data->queueMap.end()) {
7631b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        queue_data->second.eventToStageMap[event] = stageMask;
7632b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7633b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return false;
7634b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
7635b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
7636bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
76373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
763856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7639b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
76409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
76415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
76423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
7643315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1d402415);
76443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()");
76451ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETEVENT);
7646315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent()", VALIDATION_ERROR_1d400017);
7647315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdSetEvent()", VALIDATION_ERROR_1d4008fc,
7648315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1d4008fe);
76499a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
76504710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
76519b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            addCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(event), kVulkanObjectTypeEvent}, pCB);
76524710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
7653ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
76545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
7655c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
7656c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
7657c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
7658b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
7659b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, stageMask);
7660b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
76615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7662b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
76633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetEvent(commandBuffer, event, stageMask);
76645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7666bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
76673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
766856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7669b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
76709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
76715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
76723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdResetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
7673315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1c402415);
76743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()");
76751ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_RESETEVENT);
7676315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent()", VALIDATION_ERROR_1c400017);
7677315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdResetEvent()", VALIDATION_ERROR_1c400904,
7678315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1c400906);
76799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
76804710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
76819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            addCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(event), kVulkanObjectTypeEvent}, pCB);
76824710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
7683ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
76845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
7685c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
7686c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
7687c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
7688315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        // TODO : Add check for VALIDATION_ERROR_32c008f8
7689b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
7690b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, VkPipelineStageFlags(0));
7691b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
76925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7693b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
76943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdResetEvent(commandBuffer, event, stageMask);
76955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7697e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
7698e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
7699e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
7700e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkImageMemoryBarrier *pImageMemBarriers) {
7701a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    bool skip = false;
770256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(cmdBuffer), layer_data_map);
77039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, cmdBuffer);
77045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass && memBarrierCount) {
7705ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        if (!pCB->activeRenderPass->hasSelfDependency[pCB->activeSubpass]) {
7706df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
77079b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7708cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Barriers cannot be set during subpass %d "
7709cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "with no self dependency specified.",
7710a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, pCB->activeSubpass);
77115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
77125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
77145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pImageMemBarriers[i];
77158f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        auto image_data = GetImageState(dev_data, mem_barrier->image);
77168f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (image_data) {
77178f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex;
77188f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex;
77198f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            if (image_data->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
77208f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // srcQueueFamilyIndex and dstQueueFamilyIndex must both
77218f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // be VK_QUEUE_FAMILY_IGNORED
77228f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) {
77238f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
77249b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
77259b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image Barrier for image 0x%" PRIx64
77269b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         " was created with sharingMode of "
77279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "VK_SHARING_MODE_CONCURRENT. Src and dst "
77289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.",
77299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    funcName, HandleToUint64(mem_barrier->image));
77308f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                }
77318f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            } else {
77328f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and
77338f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED,
77348f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // or both be a valid queue family
77358f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) &&
77368f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    (src_q_f_index != dst_q_f_index)) {
77378f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
77389b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
77399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64
77409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         " was created with sharingMode "
77419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or "
77429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both "
77439b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "must be.",
77449b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    funcName, HandleToUint64(mem_barrier->image));
77458f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) &&
77468f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                           ((src_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
77478f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                            (dst_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()))) {
77488f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
77499b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
77508f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
77518f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    "%s: Image 0x%" PRIx64
77528f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    " was created with sharingMode "
77538f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d"
77548f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER
77558f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    "queueFamilies crated for this device.",
77569b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    funcName, HandleToUint64(mem_barrier->image), src_q_f_index, dst_q_f_index,
77578f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    dev_data->phys_dev_properties.queue_family_properties.size());
77585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
77595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
77608f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        }
77615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
77628f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (mem_barrier->oldLayout != mem_barrier->newLayout) {
77638f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            if (pCB->activeRenderPass) {
77649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |=
77659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7766315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(cmdBuffer), __LINE__, VALIDATION_ERROR_1b80093a, "DS",
77679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "%s: As the Image Barrier for image 0x%" PRIx64
77689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            " is being executed within a render pass instance, oldLayout must equal newLayout yet they are "
77699b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "%s and %s. %s",
77709b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            funcName, HandleToUint64(mem_barrier->image), string_VkImageLayout(mem_barrier->oldLayout),
7771315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            string_VkImageLayout(mem_barrier->newLayout), validation_error_map[VALIDATION_ERROR_1b80093a]);
7772d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            }
77738f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            skip |= ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source");
77748f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            skip |= ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest");
77758f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        }
77768f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
77778f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
77789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7779df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Image Layout cannot be transitioned to UNDEFINED or "
7780df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "PREINITIALIZED.",
7781df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            funcName);
77828f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        }
77838f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (image_data) {
77848f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            auto aspect_mask = mem_barrier->subresourceRange.aspectMask;
77852044b110851e8f1b75d6d406a0c88612476c63dbChris Forbes            skip |= ValidateImageAspectMask(dev_data, image_data->image, image_data->createInfo.format, aspect_mask, funcName);
778695b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski
778723c5a2092f724fef497a5c87a489f32c8fa51e58Petr Kraus            std::string param_name = "pImageMemoryBarriers[" + std::to_string(i) + "].subresourceRange";
778823c5a2092f724fef497a5c87a489f32c8fa51e58Petr Kraus            skip |= ValidateImageSubresourceRange(dev_data, image_data, nullptr, mem_barrier->subresourceRange, funcName,
778923c5a2092f724fef497a5c87a489f32c8fa51e58Petr Kraus                                                  param_name.c_str());
77905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
77915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77922044b110851e8f1b75d6d406a0c88612476c63dbChris Forbes
77935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
77945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pBufferMemBarriers[i];
77955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->activeRenderPass) {
7796df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
77979b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7798df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Buffer Barriers cannot be used during a render pass.", funcName);
77995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7800cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!mem_barrier) continue;
78015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
78025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate buffer barrier queue family indices
78035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
7804b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->srcQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
78055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
7806b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->dstQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size())) {
7807df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
78089b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
7809cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64
7810cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            " has QueueFamilyIndex greater "
7811a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.",
78129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            funcName, HandleToUint64(mem_barrier->buffer),
7813a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            dev_data->phys_dev_properties.queue_family_properties.size());
78145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
78155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
78169a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, mem_barrier->buffer);
78175cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        if (buffer_state) {
78185cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            auto buffer_size = buffer_state->requirements.size;
78195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->offset >= buffer_size) {
78209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
78219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
78229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64
78239b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                 " which is not less than total size 0x%" PRIx64 ".",
78249b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                funcName, HandleToUint64(mem_barrier->buffer), HandleToUint64(mem_barrier->offset),
78259b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(buffer_size));
7826df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
7827df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip |=
7828df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
78299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7830df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " and size 0x%" PRIx64
7831df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            " whose sum is greater than total size 0x%" PRIx64 ".",
78329b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            funcName, HandleToUint64(mem_barrier->buffer), HandleToUint64(mem_barrier->offset),
78339b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem_barrier->size), HandleToUint64(buffer_size));
78345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
78355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
78365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7837a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    return skip;
78385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7840bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool validateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex,
7841bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            VkPipelineStageFlags sourceStageMask) {
78423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
7843b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    VkPipelineStageFlags stageMask = 0;
784456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
7845b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    for (uint32_t i = 0; i < eventCount; ++i) {
78462ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event = pCB->events[firstEventIndex + i];
7847b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        auto queue_data = dev_data->queueMap.find(queue);
7848cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (queue_data == dev_data->queueMap.end()) return false;
78492ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event_data = queue_data->second.eventToStageMap.find(event);
7850b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        if (event_data != queue_data->second.eventToStageMap.end()) {
7851b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            stageMask |= event_data->second;
7852b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        } else {
78539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto global_event_data = GetEventNode(dev_data, event);
78549556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis            if (!global_event_data) {
78553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
78569b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
78579b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Event 0x%" PRIx64 " cannot be waited on if it has never been set.", HandleToUint64(event));
7858b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            } else {
78599556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis                stageMask |= global_event_data->stageMask;
7860b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            }
7861b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        }
7862b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7863c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // TODO: Need to validate that host_bit is only set if set event is called
7864c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // but set event can be called at any time.
7865c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    if (sourceStageMask != stageMask && sourceStageMask != (stageMask | VK_PIPELINE_STAGE_HOST_BIT)) {
78663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7867315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_1e62d401, "DS",
78683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Submitting cmdbuffer with call to VkCmdWaitEvents "
78693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "using srcStageMask 0x%X which must be the bitwise "
78703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "OR of the stageMask parameters used in calls to "
78713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if "
78723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "used with vkSetEvent but instead is 0x%X. %s",
7873315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        sourceStageMask, stageMask, validation_error_map[VALIDATION_ERROR_1e62d401]);
7874b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
78753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
7876b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
7877b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
787807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski// Note that we only check bits that HAVE required queueflags -- don't care entries are skipped
787907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic std::unordered_map<VkPipelineStageFlags, VkQueueFlags> supported_pipeline_stages_table = {
788007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
788107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
788207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
788307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
788407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
788507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
788607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
788707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
788807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
788907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
789007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
789107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_QUEUE_COMPUTE_BIT},
789207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT},
789307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_QUEUE_GRAPHICS_BIT}};
789407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
789507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic const VkPipelineStageFlags stage_flag_bit_array[] = {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX,
789607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
789707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
789807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
789907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
790007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
790107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
790207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
790307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
790407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
790507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
790607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
790707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TRANSFER_BIT,
790807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT};
790907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
791007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool CheckStageMaskQueueCompatibility(layer_data *dev_data, VkCommandBuffer command_buffer, VkPipelineStageFlags stage_mask,
791107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      VkQueueFlags queue_flags, const char *function, const char *src_or_dest,
791207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      UNIQUE_VALIDATION_ERROR_CODE error_code) {
791307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
791407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Lookup each bit in the stagemask and check for overlap between its table bits and queue_flags
791507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    for (const auto &item : stage_flag_bit_array) {
791607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if (stage_mask & item) {
791707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            if ((supported_pipeline_stages_table[item] & queue_flags) == 0) {
791807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                skip |=
791907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
79209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(command_buffer), __LINE__, error_code, "DL",
792107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "%s(): %s flag %s is not compatible with the queue family properties of this "
792207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "command buffer. %s",
792307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            function, src_or_dest, string_VkPipelineStageFlagBits(static_cast<VkPipelineStageFlagBits>(item)),
792407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            validation_error_map[error_code]);
792507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            }
792607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
792707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
792807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
792907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
793007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
793107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool ValidateStageMasksAgainstQueueCapabilities(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
793207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                VkPipelineStageFlags source_stage_mask, VkPipelineStageFlags dest_stage_mask,
793307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                const char *function, UNIQUE_VALIDATION_ERROR_CODE error_code) {
793407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
793507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    uint32_t queue_family_index = dev_data->commandPoolMap[cb_state->createInfo.commandPool].queueFamilyIndex;
793656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(dev_data->physical_device), instance_layer_data_map);
79379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, dev_data->physical_device);
793807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
793907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Any pipeline stage included in srcStageMask or dstStageMask must be supported by the capabilities of the queue family
794007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // specified by the queueFamilyIndex member of the VkCommandPoolCreateInfo structure that was used to create the VkCommandPool
794107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // that commandBuffer was allocated from, as specified in the table of supported pipeline stages.
794207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
794307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    if (queue_family_index < physical_device_state->queue_family_properties.size()) {
794407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        VkQueueFlags specified_queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
794507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
794607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((source_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
794707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, source_stage_mask, specified_queue_flags,
794807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "srcStageMask", error_code);
794907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
795007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((dest_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
795107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, dest_stage_mask, specified_queue_flags,
795207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "dstStageMask", error_code);
795307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
795407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
795507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
795607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
795707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
7958d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
7959d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
7960d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
7961d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
7962d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
7963d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
796456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7965b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
79669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
7967d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
7968d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= ValidateStageMasksAgainstQueueCapabilities(dev_data, cb_state, sourceStageMask, dstStageMask, "vkCmdWaitEvents",
7969315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                           VALIDATION_ERROR_1e600918);
7970315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, sourceStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_1e60090e,
7971315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1e600912);
7972315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, dstStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_1e600910,
7973315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1e600914);
7974d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        auto first_event_index = cb_state->events.size();
79755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < eventCount; ++i) {
79769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto event_state = GetEventNode(dev_data, pEvents[i]);
79774710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            if (event_state) {
79789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                addCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(pEvents[i]), kVulkanObjectTypeEvent}, cb_state);
7979d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                event_state->cb_bindings.insert(cb_state);
7980ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis            }
7981d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->waitedEvents.insert(pEvents[i]);
7982d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->events.push_back(pEvents[i]);
79835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7984d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        std::function<bool(VkQueue)> event_update =
7985d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            std::bind(validateEventStageMask, std::placeholders::_1, cb_state, eventCount, first_event_index, sourceStageMask);
7986d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        cb_state->eventUpdates.push_back(event_update);
7987baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWaitEvents()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
7988315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1e602415);
7989ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WAITEVENTS, "vkCmdWaitEvents()");
7990ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WAITEVENTS);
7991a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen        skip |=
7992a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen            ValidateBarriersToImages(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers, "vkCmdWaitEvents()");
7993e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        if (!skip) {
7994e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski            TransitionImageLayouts(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
7995e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        }
7996e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski
7997364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= ValidateBarriers("vkCmdWaitEvents()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
7998d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
79995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8000b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8001d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (!skip)
80024a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
80034a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
80044a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               imageMemoryBarrierCount, pImageMemoryBarriers);
80055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
800703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinskistatic bool PreCallValidateCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
800803122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
800903122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
801003122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
801103122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
801203122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    bool skip = false;
801303122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMasksAgainstQueueCapabilities(device_data, cb_state, srcStageMask, dstStageMask, "vkCmdPipelineBarrier",
8014315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                       VALIDATION_ERROR_1b80093e);
8015baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    skip |= ValidateCmdQueueFlags(device_data, cb_state, "vkCmdPipelineBarrier()",
8016315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_1b802415);
801703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateCmd(device_data, cb_state, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()");
8018315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateStageMaskGsTsEnables(device_data, srcStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_1b800920,
8019315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                         VALIDATION_ERROR_1b800924);
8020315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateStageMaskGsTsEnables(device_data, dstStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_1b800922,
8021315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                         VALIDATION_ERROR_1b800926);
8022a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen    skip |= ValidateBarriersToImages(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers,
8023a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen                                     "vkCmdPipelineBarrier()");
802403122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateBarriers("vkCmdPipelineBarrier()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
802503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                             pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
802603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    return skip;
802703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski}
802803122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski
80296f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinskistatic void PreCallRecordCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
80306f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski                                            uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
80316f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    UpdateCmdBufferLastCmd(cb_state, CMD_PIPELINEBARRIER);
80326f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    TransitionImageLayouts(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
80336f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski}
80346f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski
8035d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
8036d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
8037d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8038d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8039d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
8040d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
80416f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8042b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
80436f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(device_data, commandBuffer);
8044d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
80456f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        skip |= PreCallValidateCmdPipelineBarrier(device_data, cb_state, commandBuffer, srcStageMask, dstStageMask,
804603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
804703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
80486f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        if (!skip) {
80496f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski            PreCallRecordCmdPipelineBarrier(device_data, cb_state, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
80506f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        }
80516f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    } else {
80526f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        assert(0);
80535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8054b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8055a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour    if (!skip) {
8056a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour        device_data->dispatch_table.CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount,
8057a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour                                                       pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
8058a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour                                                       imageMemoryBarrierCount, pImageMemoryBarriers);
8059a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour    }
80605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8062d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool setQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value) {
806356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
80649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
8065d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (pCB) {
8066d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryToStateMap[object] = value;
8067d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8068d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8069d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (queue_data != dev_data->queueMap.end()) {
8070d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        queue_data->second.queryToStateMap[object] = value;
8071d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8072d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return false;
8073d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8074d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8075bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
80763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
807756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8078b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
80799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
80805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
80815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
80825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.insert(query);
80835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!pCB->startedQueries.count(query)) {
80845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->startedQueries.insert(query);
80855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
80863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdBeginQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8087315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_17802415);
80883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
80891ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_BEGINQUERY);
80909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
80919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, pCB);
80925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8093b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
80943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBeginQuery(commandBuffer, queryPool, slot, flags);
80955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
809789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
8098946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
809956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8100b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8101946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8102946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
81035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
8104946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (!cb_state->activeQueries.count(query)) {
8105df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8106315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1ae00652, "DS",
81079b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Ending a query before it was started: queryPool 0x%" PRIx64 ", index %d. %s",
8108315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(queryPool), slot, validation_error_map[VALIDATION_ERROR_1ae00652]);
81095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
8110946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->activeQueries.erase(query);
81115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8112946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8113946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_state->queryUpdates.push_back(query_update);
8114baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdEndQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8115315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1ae02415);
8116946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_ENDQUERY, "VkCmdEndQuery()");
8117946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_ENDQUERY);
81189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
81199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_state);
81205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8121b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8122946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdEndQuery(commandBuffer, queryPool, slot);
81235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8125bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8126bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint32_t queryCount) {
8127946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
812856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8129b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8130946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8131946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
81325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < queryCount; i++) {
81335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            QueryObject query = {queryPool, firstQuery + i};
8134946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->waitedEventsBeforeQueryReset[query] = cb_state->waitedEvents;
8135946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            std::function<bool(VkQueue)> query_update =
8136946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, false);
8137946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->queryUpdates.push_back(query_update);
8138946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        }
8139baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdResetQueryPool()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8140315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1c602415);
8141946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
8142946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_RESETQUERYPOOL);
8143315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, cb_state, "vkCmdResetQueryPool()", VALIDATION_ERROR_1c600017);
81449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
81459b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_state);
81465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8147b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8148946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
81495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8151d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool validateQuery(VkQueue queue, GLOBAL_CB_NODE *pCB, VkQueryPool queryPool, uint32_t queryCount, uint32_t firstQuery) {
81523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
815356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
8154d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8155cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (queue_data == dev_data->queueMap.end()) return false;
8156d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    for (uint32_t i = 0; i < queryCount; i++) {
8157d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        QueryObject query = {queryPool, firstQuery + i};
8158d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        auto query_data = queue_data->second.queryToStateMap.find(query);
8159d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        bool fail = false;
8160d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (query_data != queue_data->second.queryToStateMap.end()) {
8161d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (!query_data->second) {
8162d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8163d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8164d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        } else {
8165d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            auto global_query_data = dev_data->queryToStateMap.find(query);
8166d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (global_query_data != dev_data->queryToStateMap.end()) {
8167d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                if (!global_query_data->second) {
8168d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                    fail = true;
8169d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
8170d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            } else {
8171d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8172d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8173d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8174d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (fail) {
81753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
81769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
81773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Requesting a copy from query to buffer with invalid query: queryPool 0x%" PRIx64 ", index %d",
81789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(queryPool), firstQuery + i);
8179d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8180d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
81813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
8182d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8183d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8184bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8185bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
8186bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDeviceSize stride, VkQueryResultFlags flags) {
8187946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
818856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8189b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8190ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
81919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
81929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
81935cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
8194315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_19400674);
8195ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
81965cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
8197ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
8198315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
8199315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, VALIDATION_ERROR_19400672,
8200315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                     "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8201e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
82025cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
8203e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
82045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
82059f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8206946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update =
8207ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis            std::bind(validateQuery, std::placeholders::_1, cb_node, queryPool, queryCount, firstQuery);
8208946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_node->queryUpdates.push_back(query_update);
8209baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdCopyQueryPoolResults()",
8210315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_19402415);
8211946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
8212ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_COPYQUERYPOOLRESULTS);
8213315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, cb_node, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_19400017);
82149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
82159b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_node);
8216ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
8217ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
82185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8219b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8220946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
82214a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset,
82224a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                         stride, flags);
82235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
82245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8225bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags,
8226bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                            uint32_t offset, uint32_t size, const void *pValues) {
8227946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
822856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8229b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8230946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8231946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
8232baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdPushConstants()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8233315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1bc02415);
8234946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
8235946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_PUSHCONSTANTS);
82365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8237946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    skip |= validatePushConstantRange(dev_data, offset, size, "vkCmdPushConstants()");
82389e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if (0 == stageFlags) {
8239df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8240315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1bc2dc03, "DS",
8241315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "vkCmdPushConstants() call has no stageFlags set. %s", validation_error_map[VALIDATION_ERROR_1bc2dc03]);
82429e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
82439e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz
8244bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // Check if specified push constant range falls within a pipeline-defined range which has matching stageFlags.
8245bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // The spec doesn't seem to disallow having multiple push constant ranges with the
8246bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // same offset and size, but different stageFlags.  So we can't just check the
8247bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // stageFlags in the first range with matching offset and size.
8248bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    if (!skip) {
8249bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        const auto &ranges = getPipelineLayout(dev_data, layout)->push_constant_ranges;
8250bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        bool found_matching_range = false;
8251bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        for (const auto &range : ranges) {
8252bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz            if ((stageFlags == range.stageFlags) && (offset >= range.offset) && (offset + size <= range.offset + range.size)) {
8253bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz                found_matching_range = true;
825415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                break;
8255a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz            }
82569e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
8257bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        if (!found_matching_range) {
8258315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8259315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1bc002de, "DS",
8260315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            "vkCmdPushConstants() stageFlags = 0x%" PRIx32
8261315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            " do not match the stageFlags in any of the ranges with"
8262315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            " offset = %d and size = %d in pipeline layout 0x%" PRIx64 ". %s",
8263315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            (uint32_t)stageFlags, offset, size, HandleToUint64(layout),
8264315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1bc002de]);
826515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        }
82665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8267b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8268946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
82695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
82705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8271bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
8272bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             VkQueryPool queryPool, uint32_t slot) {
8273946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
827456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8275b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8276946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8277946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
82785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
8279946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8280946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_state->queryUpdates.push_back(query_update);
8281baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWriteTimestamp()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8282315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1e802415);
8283946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
8284946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WRITETIMESTAMP);
82855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8286b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8287946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
82885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
82895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
82906600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinskistatic bool MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference *attachments,
82919bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       const VkFramebufferCreateInfo *fbci, VkImageUsageFlagBits usage_flag,
82929bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
8293946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
82946600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
82956600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    for (uint32_t attach = 0; attach < count; attach++) {
82966600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        if (attachments[attach].attachment != VK_ATTACHMENT_UNUSED) {
82976600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Attachment counts are verified elsewhere, but prevent an invalid access
82986600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (attachments[attach].attachment < fbci->attachmentCount) {
82996600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                const VkImageView *image_view = &fbci->pAttachments[attachments[attach].attachment];
83009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, *image_view);
830179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (view_state) {
83029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    const VkImageCreateInfo *ici = &GetImageState(dev_data, view_state->create_info.image)->createInfo;
83036600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    if (ici != nullptr) {
83046600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        if ((ici->usage & usage_flag) == 0) {
8305df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
8306df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                            VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, error_code, "DS",
8307946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "vkCreateFramebuffer:  Framebuffer Attachment (%d) conflicts with the image's "
8308946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "IMAGE_USAGE flags (%s). %s",
8309946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            attachments[attach].attachment, string_VkImageUsageFlagBits(usage_flag),
8310946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            validation_error_map[error_code]);
83116600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        }
83126600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    }
83136600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                }
83146600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
83156600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
83166600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
8317946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    return skip;
83186600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
83196600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
8320d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// Validate VkFramebufferCreateInfo which includes:
8321d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// 1. attachmentCount equals renderPass attachmentCount
83225ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 2. corresponding framebuffer and renderpass attachments have matching formats
83235ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 3. corresponding framebuffer and renderpass attachments have matching sample counts
83245ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 4. fb attachments only have a single mip level
83255ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 5. fb attachment dimensions are each at least as large as the fb
83265ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 6. fb attachments use idenity swizzle
83275ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 7. fb attachments used by renderPass for color/input/ds have correct usage bit set
83286fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis// 8. fb dimensions are within physical device limits
8329d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlisstatic bool ValidateFramebufferCreateInfo(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
83303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
83316600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
83329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto rp_state = GetRenderPassState(dev_data, pCreateInfo->renderPass);
8333127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    if (rp_state) {
8334127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        const VkRenderPassCreateInfo *rpci = rp_state->createInfo.ptr();
8335d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        if (rpci->attachmentCount != pCreateInfo->attachmentCount) {
83363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(
8337d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
8338315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                HandleToUint64(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_094006d8, "DS",
8339d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachmentCount of %u does not match attachmentCount of %u of "
83409bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "renderPass (0x%" PRIxLEAST64 ") being used to create Framebuffer. %s",
83419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                pCreateInfo->attachmentCount, rpci->attachmentCount, HandleToUint64(pCreateInfo->renderPass),
8342315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                validation_error_map[VALIDATION_ERROR_094006d8]);
83435ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        } else {
834441ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis            // attachmentCounts match, so make sure corresponding attachment details line up
83455ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            const VkImageView *image_views = pCreateInfo->pAttachments;
83465ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
83479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, image_views[i]);
834812d5600c2f9e32343016fd944432ba95df370797Tobin Ehlis                auto &ivci = view_state->create_info;
834979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.format != rpci->pAttachments[i].format) {
83503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
83515ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
8352315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_094006e0, "DS",
83539bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has format of %s that does not match "
83549bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the format of "
83559bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
835679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkFormat(ivci.format), string_VkFormat(rpci->pAttachments[i].format),
8357315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_094006e0]);
83585ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
83599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                const VkImageCreateInfo *ici = &GetImageState(dev_data, ivci.image)->createInfo;
83605ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                if (ici->samples != rpci->pAttachments[i].samples) {
83613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
836241ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
8363315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_094006e2, "DS",
83649bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has %s samples that do not match "
83659bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the %s samples used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
836641ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        i, string_VkSampleCountFlagBits(ici->samples), string_VkSampleCountFlagBits(rpci->pAttachments[i].samples),
8367315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_094006e2]);
83685ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
83695ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                // Verify that view only has a single mip level
837079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.subresourceRange.levelCount != 1) {
83713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
8372315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_094006e6, "DS",
83733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has mip levelCount of %u "
83743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "but only a single mip level (levelCount ==  1) is allowed when creating a Framebuffer. %s",
8375315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, ivci.subresourceRange.levelCount, validation_error_map[VALIDATION_ERROR_094006e6]);
83765ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
837779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                const uint32_t mip_level = ivci.subresourceRange.baseMipLevel;
8378aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_width = max(1u, ici->extent.width >> mip_level);
8379aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_height = max(1u, ici->extent.height >> mip_level);
838079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if ((ivci.subresourceRange.layerCount < pCreateInfo->layers) || (mip_width < pCreateInfo->width) ||
8381aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    (mip_height < pCreateInfo->height)) {
83822c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                    skip |= log_msg(
83832c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8384315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006e4, "DS",
83852c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has dimensions smaller "
83862c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "than the corresponding framebuffer dimensions. Here are the respective dimensions for attachment #%u, "
83872c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "framebuffer:\n"
83882c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "width: %u, %u\n"
83892c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "height: %u, %u\n"
83902c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "layerCount: %u, %u\n%s",
83912c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        i, ivci.subresourceRange.baseMipLevel, i, mip_width, pCreateInfo->width, mip_height, pCreateInfo->height,
8392315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        ivci.subresourceRange.layerCount, pCreateInfo->layers, validation_error_map[VALIDATION_ERROR_094006e4]);
83935ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
839479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (((ivci.components.r != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.r != VK_COMPONENT_SWIZZLE_R)) ||
839579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.g != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.g != VK_COMPONENT_SWIZZLE_G)) ||
839679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.b != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.b != VK_COMPONENT_SWIZZLE_B)) ||
839779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.a != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.a != VK_COMPONENT_SWIZZLE_A))) {
83983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
83995b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8400315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006e8, "DS",
8401da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has non-identy swizzle. All framebuffer "
8402da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "attachments must have been created with the identity swizzle. Here are the actual swizzle values:\n"
8403da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "r swizzle = %s\n"
8404da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "g swizzle = %s\n"
8405da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "b swizzle = %s\n"
84069bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "a swizzle = %s\n"
84079bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s",
840879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkComponentSwizzle(ivci.components.r), string_VkComponentSwizzle(ivci.components.g),
84099bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        string_VkComponentSwizzle(ivci.components.b), string_VkComponentSwizzle(ivci.components.a),
8410315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006e8]);
84115ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
84125ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            }
8413d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        }
84145ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        // Verify correct attachment usage flags
84156600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        for (uint32_t subpass = 0; subpass < rpci->subpassCount; subpass++) {
84166600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify input attachments:
84173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
84189bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].inputAttachmentCount, rpci->pSubpasses[subpass].pInputAttachments,
8419315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           pCreateInfo, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VALIDATION_ERROR_094006de);
84206600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify color attachments:
84213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
84229bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].colorAttachmentCount, rpci->pSubpasses[subpass].pColorAttachments,
8423315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           pCreateInfo, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VALIDATION_ERROR_094006da);
84246600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify depth/stencil attachments:
84256600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (rpci->pSubpasses[subpass].pDepthStencilAttachment != nullptr) {
84263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= MatchUsage(dev_data, 1, rpci->pSubpasses[subpass].pDepthStencilAttachment, pCreateInfo,
8427315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                   VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VALIDATION_ERROR_094006dc);
84286600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
84296600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
84306600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
84316fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    // Verify FB dimensions are within physical device limits
84329bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->width > dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth) {
84333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8434315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006ec, "DS",
84353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width exceeds physical device limits. "
84363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested width: %u, device max: %u\n"
84373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
84383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->width, dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth,
8439315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006ec]);
84409bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
84419bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->height > dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight) {
84423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8443315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006f0, "DS",
84443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height exceeds physical device limits. "
84453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested height: %u, device max: %u\n"
84463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
84473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->height, dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight,
8448315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006f0]);
84499bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
84509bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->layers > dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers) {
84513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8452315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006f4, "DS",
84533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers exceeds physical device limits. "
84543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested layers: %u, device max: %u\n"
84553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
84563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->layers, dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers,
8457315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006f4]);
84586fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    }
8459c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    // Verify FB dimensions are greater than zero
8460c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->width <= 0) {
8461c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8462315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006ea, "DS",
8463c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width must be greater than zero. %s",
8464315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006ea]);
8465c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
8466c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->height <= 0) {
8467c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8468315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006ee, "DS",
8469c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height must be greater than zero. %s",
8470315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006ee]);
8471c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
8472c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->layers <= 0) {
8473c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8474315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006f2, "DS",
8475c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers must be greater than zero. %s",
8476315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006f2]);
8477c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
84783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
84796600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
84806600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
848164c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis// Validate VkFramebufferCreateInfo state prior to calling down chain to create Framebuffer object
848264c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//  Return true if an error is encountered and callback returns true to skip call down chain
848364c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//   false indicates that call down chain should proceed
848464c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlisstatic bool PreCallValidateCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
848564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    // TODO : Verify that renderPass FB is created with is compatible with FB
84863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
84873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateFramebufferCreateInfo(dev_data, pCreateInfo);
84883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
848964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis}
849064c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
849154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis// CreateFramebuffer state has been validated and call down chain completed so record new framebuffer object
849254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlisstatic void PostCallRecordCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo, VkFramebuffer fb) {
849354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    // Shadow create info and store in map
8494c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    std::unique_ptr<FRAMEBUFFER_STATE> fb_state(
8495c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        new FRAMEBUFFER_STATE(fb, pCreateInfo, dev_data->renderPassMap[pCreateInfo->renderPass]->createInfo.ptr()));
849676f04ca0e692f9f15d5ef7e0c658c24d11f34ebcTobin Ehlis
849754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
849854e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        VkImageView view = pCreateInfo->pAttachments[i];
84999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, view);
850079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        if (!view_state) {
850154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis            continue;
850254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        }
850354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        MT_FB_ATTACHMENT_INFO fb_info;
8504883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        fb_info.view_state = view_state;
850579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        fb_info.image = view_state->create_info.image;
8506c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        fb_state->attachments.push_back(fb_info);
850754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    }
8508c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    dev_data->frameBufferMap[fb] = std::move(fb_state);
850954e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis}
851054e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis
851189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
8512bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) {
851356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
851464c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
85153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateCreateFramebuffer(dev_data, pCreateInfo);
851664c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    lock.unlock();
851764c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
85183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
851964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
85204a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
85216600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
85225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
852364c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis        lock.lock();
852454e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        PostCallRecordCreateFramebuffer(dev_data, pCreateInfo, *pFramebuffer);
852554e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        lock.unlock();
85265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
85275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
85285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
85304e11bb1277f55311686a42000520791e1db1dd7bbungemanstatic bool FindDependency(const uint32_t index, const uint32_t dependent, const std::vector<DAGNode> &subpass_to_node,
8531e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           std::unordered_set<uint32_t> &processed_nodes) {
85325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If we have already checked this node we have not found a dependency path so return false.
8533cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (processed_nodes.count(index)) return false;
85345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    processed_nodes.insert(index);
85355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
85365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Look for a dependency path. If one exists return true else recurse on the previous nodes.
85374e11bb1277f55311686a42000520791e1db1dd7bbungeman    if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) {
85385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto elem : node.prev) {
8539cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) return true;
85405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
85415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
8542e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        return true;
85435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8544e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
85455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
85474e11bb1277f55311686a42000520791e1db1dd7bbungemanstatic bool CheckDependencyExists(const layer_data *dev_data, const uint32_t subpass,
85483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                  const std::vector<uint32_t> &dependent_subpasses, const std::vector<DAGNode> &subpass_to_node,
85493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                  bool &skip) {
8550e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = true;
85515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through all subpasses that share the same attachment and make sure a dependency exists
85525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
8553cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (static_cast<uint32_t>(subpass) == dependent_subpasses[k]) continue;
85545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const DAGNode &node = subpass_to_node[subpass];
85555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Check for a specified dependency between the two nodes. If one exists we are done.
85565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]);
85575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]);
85585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
85597655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            // If no dependency exits an implicit dependency still might. If not, throw an error.
85605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            std::unordered_set<uint32_t> processed_nodes;
85617655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            if (!(FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) ||
8562bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                  FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes))) {
85633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
85643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
85653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "A dependency between subpasses %d and %d must exist but one is not specified.", subpass,
85663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                dependent_subpasses[k]);
8567e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                result = false;
85685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
85695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
85705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
85715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
85725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
85748860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, const int index,
85753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip) {
85765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
85775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If this node writes to the attachment return true as next nodes need to preserve the attachment.
85785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
85795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
8580cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pColorAttachments[j].attachment) return true;
85815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8582a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
8583a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour        if (attachment == subpass.pInputAttachments[j].attachment) return true;
8584a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    }
85855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
8586cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pDepthStencilAttachment->attachment) return true;
85875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8588e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
85895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through previous nodes and see if any of them write to the attachment.
85905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto elem : node.prev) {
85913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        result |= CheckPreserved(dev_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip);
85925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
85935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If the attachment was written to by a previous node than this node needs to preserve it.
85945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result && depth > 0) {
8595e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        bool has_preserved = false;
85965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
85975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (subpass.pPreserveAttachments[j] == attachment) {
8598e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                has_preserved = true;
85995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                break;
86005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8602e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        if (!has_preserved) {
86033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
86043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
86053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
86065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
86075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
86085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
86095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8611cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class T>
8612cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskibool isRangeOverlapping(T offset1, T size1, T offset2, T size2) {
86135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
86145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis           ((offset1 > offset2) && (offset1 < (offset2 + size2)));
86155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
86175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
86185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
86195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
86205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8622c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE const *framebuffer,
8623127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                 RENDER_PASS_STATE const *renderPass) {
86243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
8625fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pFramebufferInfo = framebuffer->createInfo.ptr();
8626fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pCreateInfo = renderPass->createInfo.ptr();
8627bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto const &subpass_to_node = renderPass->subpassToNode;
86285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount);
86295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount);
86305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount);
86315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find overlapping attachments
86325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
86335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) {
86345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewi = pFramebufferInfo->pAttachments[i];
86355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewj = pFramebufferInfo->pAttachments[j];
86365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (viewi == viewj) {
86375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
86385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
86395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
86405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_i = GetImageViewState(dev_data, viewi);
86429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_j = GetImageViewState(dev_data, viewj);
864379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (!view_state_i || !view_state_j) {
86445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
86455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
864679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_i = view_state_i->create_info;
864779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_j = view_state_j->create_info;
864879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (view_ci_i.image == view_ci_j.image && isRegionOverlapping(view_ci_i.subresourceRange, view_ci_j.subresourceRange)) {
86495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
86505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
86515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
86525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_i = GetImageState(dev_data, view_ci_i.image);
86549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_j = GetImageState(dev_data, view_ci_j.image);
86556d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (!image_data_i || !image_data_j) {
86565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
86575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8658e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            if (image_data_i->binding.mem == image_data_j->binding.mem &&
8659e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                isRangeOverlapping(image_data_i->binding.offset, image_data_i->binding.size, image_data_j->binding.offset,
8660e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                                   image_data_j->binding.size)) {
86615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
86625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
86635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
86655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
86665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
86675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t attachment = i;
86685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto other_attachment : overlapping_attachments[i]) {
86695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
86709b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
8671315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(framebuffer->framebuffer), __LINE__, VALIDATION_ERROR_12200682, "DS",
86729b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Attachment %d aliases attachment %d but doesn't "
86739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
8674315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                attachment, other_attachment, validation_error_map[VALIDATION_ERROR_12200682]);
86755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
86779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
8678315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(framebuffer->framebuffer), __LINE__, VALIDATION_ERROR_12200682, "DS",
86799b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Attachment %d aliases attachment %d but doesn't "
86809b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
8681315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                other_attachment, attachment, validation_error_map[VALIDATION_ERROR_12200682]);
86825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
86845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
86855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find for each attachment the subpasses that use them.
86861c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young    unordered_set<uint32_t> attachmentIndices;
86875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
86885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
86891c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young        attachmentIndices.clear();
86905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
86915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pInputAttachments[j].attachment;
8692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
86935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            input_attachment_to_subpass[attachment].push_back(i);
86945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
86955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                input_attachment_to_subpass[overlapping_attachment].push_back(i);
86965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
86985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
86995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pColorAttachments[j].attachment;
8700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
87015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
87025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
87035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
87045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
87051c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            attachmentIndices.insert(attachment);
87065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
87085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
87095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
87105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
87115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
87125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
87131c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young
87141c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            if (attachmentIndices.count(attachment)) {
87153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
8716df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8717df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
87188860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                            "Cannot use same attachment (%u) as both color and depth output in same subpass (%u).", attachment, i);
87191c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            }
87205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If there is a dependency needed make sure one exists
87235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
87245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
87255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an input then all subpasses that output must have a dependency relationship
87265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
872793fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pInputAttachments[j].attachment;
8728cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
87293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
87305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
87325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
873393fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pColorAttachments[j].attachment;
8734cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
87353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
87363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip);
87375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
87395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
87403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
87413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip);
87425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
87455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // written.
87465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
87475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
87485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
87493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckPreserved(dev_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip);
87505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
87535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
875532f68580aa01aab3e923cb52915a1d3dd4e993c5Chris Forbesstatic bool CreatePassDAG(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo,
8756e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                          std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) {
87573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
87585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
87595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        DAGNode &subpass_node = subpass_to_node[i];
87605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        subpass_node.pass = i;
87615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
87635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
876466a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL || dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
876566a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            if (dependency.srcSubpass == dependency.dstSubpass) {
87663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
8767df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8768df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external.");
876966a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            }
877066a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        } else if (dependency.srcSubpass > dependency.dstSubpass) {
87713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
87723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
87733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Depedency graph must be specified such that an earlier pass cannot depend on a later pass.");
87745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (dependency.srcSubpass == dependency.dstSubpass) {
87755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            has_self_dependency[dependency.srcSubpass] = true;
87765c6aacf95832467d52b2fde1130b04bef559573aChris Forbes        } else {
87775c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
87785c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
87795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
87825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8783918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
878489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
8785bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
878656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
87873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
8788c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    spv_result_t spv_valid = SPV_SUCCESS;
8789b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
8790e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    if (!GetDisables(dev_data)->shader_validation) {
8791a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski        if (!dev_data->extensions.vk_nv_glsl_shader && (pCreateInfo->codeSize % 4)) {
87920fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8793315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_12a00ac0, "SC",
87940fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                            "SPIR-V module not valid: Codesize must be a multiple of 4 but is " PRINTF_SIZE_T_SPECIFIER ". %s",
8795315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCreateInfo->codeSize, validation_error_map[VALIDATION_ERROR_12a00ac0]);
87960fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski        } else {
87970fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            // Use SPIRV-Tools validator to try and catch any issues with the module itself
87980fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spv_context ctx = spvContextCreate(SPV_ENV_VULKAN_1_0);
87990fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spv_const_binary_t binary{ pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t) };
88000fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spv_diagnostic diag = nullptr;
88010fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski
88020fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spv_valid = spvValidate(ctx, &binary, &diag);
88030fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            if (spv_valid != SPV_SUCCESS) {
8804a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski                if (!dev_data->extensions.vk_nv_glsl_shader || (pCreateInfo->pCode[0] == spv::MagicNumber)) {
88050fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                    skip |= log_msg(dev_data->report_data,
88060fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                        spv_valid == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
88070fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                        VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
88080fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                        "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
88090fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                }
8810c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski            }
88115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
88120fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spvDiagnosticDestroy(diag);
88130fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spvContextDestroy(ctx);
88140fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski        }
8815b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
88163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
8817e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    }
88185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
88194a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult res = dev_data->dispatch_table.CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
88205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
882159ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis    if (res == VK_SUCCESS) {
8822b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
8823c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        const auto new_shader_module = (SPV_SUCCESS == spv_valid ? new shader_module(pCreateInfo) : new shader_module());
8824c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        dev_data->shaderModuleMap[*pShaderModule] = unique_ptr<shader_module>(new_shader_module);
88255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
88265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
88275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
88285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
88294f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateAttachmentIndex(layer_data *dev_data, uint32_t attachment, uint32_t attachment_count, const char *type) {
88303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
88314f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (attachment >= attachment_count && attachment != VK_ATTACHMENT_UNUSED) {
88323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8833315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_12200684, "DS",
88343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "CreateRenderPass: %s attachment %d must be less than the total number of attachments %d. %s", type,
8835315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        attachment, attachment_count, validation_error_map[VALIDATION_ERROR_12200684]);
88364f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
88373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
88384f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
88394f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
8840bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool IsPowerOfTwo(unsigned x) { return x && !(x & (x - 1)); }
8841805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
88424f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateRenderpassAttachmentUsage(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo) {
88433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
88444f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
88454f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
88464f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS) {
88473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8848315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_14000698, "DS",
88493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "CreateRenderPass: Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS. %s", i,
8850315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_14000698]);
88514f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
8852ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
88534f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
88544f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pPreserveAttachments[j];
88554f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) {
88563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8857315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_140006aa, "DS",
88583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "CreateRenderPass:  Preserve attachment (%d) must not be VK_ATTACHMENT_UNUSED. %s", j,
8859315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_140006aa]);
88604f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            } else {
88613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Preserve");
8862ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
8863ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                bool found = (subpass.pDepthStencilAttachment != NULL && subpass.pDepthStencilAttachment->attachment == attachment);
8864ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                for (uint32_t r = 0; !found && r < subpass.inputAttachmentCount; ++r) {
8865ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    found = (subpass.pInputAttachments[r].attachment == attachment);
8866ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
8867ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                for (uint32_t r = 0; !found && r < subpass.colorAttachmentCount; ++r) {
8868ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    found = (subpass.pColorAttachments[r].attachment == attachment) ||
8869ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                            (subpass.pResolveAttachments != NULL && subpass.pResolveAttachments[r].attachment == attachment);
8870ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
8871ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                if (found) {
8872ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    skip |= log_msg(
8873ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8874315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_140006ac, "DS",
8875ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                        "CreateRenderPass: subpass %u pPreserveAttachments[%u] (%u) must not be used elsewhere in the subpass. %s",
8876315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        i, j, attachment, validation_error_map[VALIDATION_ERROR_140006ac]);
8877ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
88784f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
88794f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
88806a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
8881bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto subpass_performs_resolve =
8882bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            subpass.pResolveAttachments &&
8883bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            std::any_of(subpass.pResolveAttachments, subpass.pResolveAttachments + subpass.colorAttachmentCount,
8884bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        [](VkAttachmentReference ref) { return ref.attachment != VK_ATTACHMENT_UNUSED; });
88856a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
8886805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        unsigned sample_count = 0;
8887805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
88884f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
88894f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment;
88904f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (subpass.pResolveAttachments) {
88914f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                attachment = subpass.pResolveAttachments[j].attachment;
88923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Resolve");
88936a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
88943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                if (!skip && attachment != VK_ATTACHMENT_UNUSED &&
88956a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    pCreateInfo->pAttachments[attachment].samples != VK_SAMPLE_COUNT_1_BIT) {
88963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
8897315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_140006a2, "DS",
88983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "CreateRenderPass:  Subpass %u requests multisample resolve into attachment %u, "
88993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "which must have VK_SAMPLE_COUNT_1_BIT but has %s. %s",
89003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    i, attachment, string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment].samples),
8901315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_140006a2]);
89026a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                }
8903ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
8904ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                if (!skip && subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED &&
8905ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    subpass.pColorAttachments[j].attachment == VK_ATTACHMENT_UNUSED) {
8906ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
8907315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_1400069e, "DS",
8908ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                                    "CreateRenderPass:  Subpass %u requests multisample resolve from attachment %u "
8909ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                                    "which has attachment=VK_ATTACHMENT_UNUSED. %s",
8910315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, attachment, validation_error_map[VALIDATION_ERROR_1400069e]);
8911ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
89124f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
89134f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            attachment = subpass.pColorAttachments[j].attachment;
89143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Color");
89156a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
89163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            if (!skip && attachment != VK_ATTACHMENT_UNUSED) {
8917805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
8918805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
8919bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (subpass_performs_resolve && pCreateInfo->pAttachments[attachment].samples == VK_SAMPLE_COUNT_1_BIT) {
89203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
8921315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_140006a0, "DS",
89223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "CreateRenderPass:  Subpass %u requests multisample resolve from attachment %u "
89233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "which has VK_SAMPLE_COUNT_1_BIT. %s",
8924315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, attachment, validation_error_map[VALIDATION_ERROR_140006a0]);
8925dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                }
8926ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
8927ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                if (subpass_performs_resolve && subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED) {
8928ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    const auto &color_desc = pCreateInfo->pAttachments[attachment];
8929ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    const auto &resolve_desc = pCreateInfo->pAttachments[subpass.pResolveAttachments[j].attachment];
8930ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    if (color_desc.format != resolve_desc.format) {
8931315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        skip |=
8932315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
8933315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_140006a4, "DS",
8934315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    "CreateRenderPass:  Subpass %u pColorAttachments[%u] resolves to an attachment with a "
8935315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    "different format. "
8936315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    "color format: %u, resolve format: %u. %s",
8937315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, j, color_desc.format, resolve_desc.format, validation_error_map[VALIDATION_ERROR_140006a4]);
8938ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    }
8939ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
89406a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes            }
89414f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
8942dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
89434f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
89444f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
89453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Depth stencil");
8946805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
89473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            if (!skip && attachment != VK_ATTACHMENT_UNUSED) {
8948805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
8949805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            }
89504f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
8951dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
89524f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
89534f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pInputAttachments[j].attachment;
89543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Input");
89554f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
8956805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
8957805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        if (sample_count && !IsPowerOfTwo(sample_count)) {
89583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8959315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_0082b401, "DS",
89603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "CreateRenderPass:  Subpass %u attempts to render to "
89613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "attachments with inconsistent sample counts. %s",
8962315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            i, validation_error_map[VALIDATION_ERROR_0082b401]);
8963805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        }
89644f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
89653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
89664f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
89674f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
89685245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbesstatic void MarkAttachmentFirstUse(RENDER_PASS_STATE *render_pass,
89695245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                                   uint32_t index,
89705245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                                   bool is_read) {
89715245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes    if (index == VK_ATTACHMENT_UNUSED)
89725245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes        return;
89735245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes
89745245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes    if (!render_pass->attachment_first_read.count(index))
89755245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes        render_pass->attachment_first_read[index] = is_read;
89765245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes}
89775245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes
897889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
89794f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
89803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
898156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
89824f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
89834f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
89844f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    // TODO: As part of wrapping up the mem_tracker/core_validation merge the following routine should be consolidated with
89854f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    //       ValidateLayouts.
89863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateRenderpassAttachmentUsage(dev_data, pCreateInfo);
8987208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
89883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].srcStageMask, "vkCreateRenderPass()",
8989315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_13e006b8, VALIDATION_ERROR_13e006bc);
89903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].dstStageMask, "vkCreateRenderPass()",
8991315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_13e006ba, VALIDATION_ERROR_13e006be);
8992208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
89933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
89943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateLayouts(dev_data, device, pCreateInfo);
8995ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    }
8996ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes    lock.unlock();
89974f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
89983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
89994f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
90004f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
90014f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
90024a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
9003ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes
90045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
90054f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        lock.lock();
90064f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
90074f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<bool> has_self_dependency(pCreateInfo->subpassCount);
90084f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount);
900932f68580aa01aab3e923cb52915a1d3dd4e993c5Chris Forbes        skip |= CreatePassDAG(dev_data, pCreateInfo, subpass_to_node, has_self_dependency);
90104f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9011127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        auto render_pass = unique_ptr<RENDER_PASS_STATE>(new RENDER_PASS_STATE(pCreateInfo));
901298cddf7090b5d5dcc382045867753ef703d1c3d3Chris Forbes        render_pass->renderPass = *pRenderPass;
9013cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->hasSelfDependency = has_self_dependency;
9014cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->subpassToNode = subpass_to_node;
9015db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
901687e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
901787e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
901887e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
90195245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pColorAttachments[j].attachment, false);
90209cde292b1c19c643b7c13018d9834cccfe6ef7eaChris Forbes
90215245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                // resolve attachments are considered to be written
90225245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                if (subpass.pResolveAttachments) {
90235245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                    MarkAttachmentFirstUse(render_pass.get(), subpass.pResolveAttachments[j].attachment, false);
90249cde292b1c19c643b7c13018d9834cccfe6ef7eaChris Forbes                }
902587e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
90265245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes            if (subpass.pDepthStencilAttachment) {
90275245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pDepthStencilAttachment->attachment, false);
902887e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
9029a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
90305245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pInputAttachments[j].attachment, true);
9031a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            }
903287e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        }
9033db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
9034fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        dev_data->renderPassMap[*pRenderPass] = std::move(render_pass);
90355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
90375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90384f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9039eb4c61477130f69f48fdf3ac31cb82104181cc73Chris Forbesstatic bool validatePrimaryCommandBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, char const *cmd_name,
90409bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         UNIQUE_VALIDATION_ERROR_CODE error_code) {
90413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
90425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
90433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
90449b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCB->commandBuffer), __LINE__, error_code, "DS",
90459b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "Cannot execute command %s on a secondary command buffer. %s", cmd_name, validation_error_map[error_code]);
90465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
90485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
90508860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool VerifyRenderAreaBounds(const layer_data *dev_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
90513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9052c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    const safe_VkFramebufferCreateInfo *pFramebufferInfo =
90539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        &GetFramebufferState(dev_data, pRenderPassBegin->framebuffer)->createInfo;
9054885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    if (pRenderPassBegin->renderArea.offset.x < 0 ||
9055885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > pFramebufferInfo->width ||
9056885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        pRenderPassBegin->renderArea.offset.y < 0 ||
9057885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.y + pRenderPassBegin->renderArea.extent.height) > pFramebufferInfo->height) {
90583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= static_cast<bool>(log_msg(
9059df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
9060885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            DRAWSTATE_INVALID_RENDER_AREA, "CORE",
9061885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "Cannot execute a render pass with renderArea not within the bound of the "
9062885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "framebuffer. RenderArea: x %d, y %d, width %d, height %d. Framebuffer: width %d, "
9063885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "height %d.",
9064885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.width,
9065885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.extent.height, pFramebufferInfo->width, pFramebufferInfo->height));
9066885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    }
90673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
9068885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine}
9069885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine
90701a65650f856376768d7b03ea2d080aaff87cacfdMark 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
90711a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// [load|store]Op flag must be checked
90721a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// TODO: The memory valid flag in DEVICE_MEM_INFO should probably be split to track the validity of stencil memory separately.
9073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <typename T>
9074cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool FormatSpecificLoadAndStoreOpSettings(VkFormat format, T color_depth_op, T stencil_op, T op) {
9075a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    if (color_depth_op != op && stencil_op != op) {
9076a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski        return false;
9077a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    }
907816769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton    bool check_color_depth_load_op = !FormatIsStencilOnly(format);
907916769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton    bool check_stencil_load_op = FormatIsDepthAndStencil(format) || !check_color_depth_load_op;
9080a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski
90810d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes    return ((check_color_depth_load_op && (color_depth_op == op)) ||
90820d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes            (check_stencil_load_op && (stencil_op == op)));
90831a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski}
90841a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski
9085bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
9086bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkSubpassContents contents) {
90873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
908856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9089b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
90909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
90919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr;
90929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr;
9093f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
9094308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski        if (render_pass_state) {
9095cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            uint32_t clear_op_size = 0;  // Make sure pClearValues is at least as large as last LOAD_OP_CLEAR
9096f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeFramebuffer = pRenderPassBegin->framebuffer;
9097308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            for (uint32_t i = 0; i < render_pass_state->createInfo.attachmentCount; ++i) {
9098f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9099308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                auto pAttachment = &render_pass_state->createInfo.pAttachments[i];
9100bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp, pAttachment->stencilLoadOp,
91011a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski                                                         VK_ATTACHMENT_LOAD_OP_CLEAR)) {
910292bc0680357019834b7529148ab6d73353ce02c7Mark Lobodzinski                    clear_op_size = static_cast<uint32_t>(i) + 1;
910316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
91049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
910516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
910616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9107f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9108db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9109bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE)) {
911016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
91119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
911216387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
911316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9114f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9115db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9116bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD)) {
911716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
91189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9119f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
912016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9121f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
912216387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                }
9123308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                if (render_pass_state->attachment_first_read[i]) {
912416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
91259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9126f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
912716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9128f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
91295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
91305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
91316de3c6ffa0819ee37cd5cecee918b062145e2ff1Tobin Ehlis            if (clear_op_size > pRenderPassBegin->clearValueCount) {
91323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
9133369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
9134315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    HandleToUint64(render_pass_state->renderPass), __LINE__, VALIDATION_ERROR_1200070c, "DS",
9135bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but there must "
9136bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "be at least %u entries in pClearValues array to account for the highest index attachment in renderPass "
9137cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "0x%" PRIx64
9138cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array "
9139bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "is indexed by attachment number so even if some pClearValues entries between 0 and %u correspond to "
9140bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "attachments that aren't cleared they will be ignored. %s",
91419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    pRenderPassBegin->clearValueCount, clear_op_size, HandleToUint64(render_pass_state->renderPass), clear_op_size,
9142315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    clear_op_size - 1, validation_error_map[VALIDATION_ERROR_1200070c]);
9143369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            }
91443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin);
91453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= VerifyFramebufferAndRenderPassLayouts(dev_data, cb_node, pRenderPassBegin,
91463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                          GetFramebufferState(dev_data, pRenderPassBegin->framebuffer));
9147315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= insideRenderPass(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_17a00017);
91483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateDependencies(dev_data, framebuffer, render_pass_state);
9149315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= validatePrimaryCommandBuffer(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_17a00019);
9150315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBeginRenderPass()", VK_QUEUE_GRAPHICS_BIT,
9151315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                          VALIDATION_ERROR_17a02415);
91523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateCmd(dev_data, cb_node, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()");
91531ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(cb_node, CMD_BEGINRENDERPASS);
9154308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            cb_node->activeRenderPass = render_pass_state;
91555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // This is a shallow copy as that is all that is needed for now
9156f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeRenderPassBeginInfo = *pRenderPassBegin;
9157f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpass = 0;
9158f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpassContents = contents;
9159f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->framebuffers.insert(pRenderPassBegin->framebuffer);
9160883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            // Connect this framebuffer and its children to this cmdBuffer
9161883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            AddFramebufferBinding(dev_data, cb_node, framebuffer);
91625f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis            // transition attachments to the correct layouts for beginning of renderPass and first subpass
91635f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis            TransitionBeginRenderPassLayouts(dev_data, cb_node, render_pass_state, framebuffer);
91645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9166b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
91673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
91684a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
91695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
91715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
917289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
91733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
917456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9175b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
91769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
91775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
9178315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_1b600019);
9179315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdNextSubpass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1b602415);
91803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()");
91811ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_NEXTSUBPASS);
9182315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_1b600017);
918380281691386b37385846f21b38e8c9d4b12cc74eChris Forbes
9184fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        auto subpassCount = pCB->activeRenderPass->createInfo.subpassCount;
918580281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        if (pCB->activeSubpass == subpassCount - 1) {
91863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9187315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1b60071a, "DS",
91883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdNextSubpass(): Attempted to advance beyond final subpass. %s",
9189315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1b60071a]);
919080281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        }
91915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9192b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
919396ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
91943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
919596ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
91964a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdNextSubpass(commandBuffer, contents);
919796ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
919896ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    if (pCB) {
9199bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        lock.lock();
9200bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpass++;
9201bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpassContents = contents;
92025f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis        TransitionSubpassLayouts(dev_data, pCB, pCB->activeRenderPass, pCB->activeSubpass,
92039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                 GetFramebufferState(dev_data, pCB->activeRenderPassBeginInfo.framebuffer));
920496ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    }
92055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
92065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
920789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) {
92083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
920956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9210b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
92119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pCB = GetCBNode(dev_data, commandBuffer);
921255867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski    FRAMEBUFFER_STATE *framebuffer = NULL;
921358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes    if (pCB) {
9214127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        RENDER_PASS_STATE *rp_state = pCB->activeRenderPass;
92159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        framebuffer = GetFramebufferState(dev_data, pCB->activeFramebuffer);
9216127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        if (rp_state) {
9217127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            if (pCB->activeSubpass != rp_state->createInfo.subpassCount - 1) {
92183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
92199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
9220315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                VALIDATION_ERROR_1b00071c, "DS", "vkCmdEndRenderPass(): Called before reaching final subpass. %s",
9221315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_1b00071c]);
922202a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes            }
922302a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes
9224127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            for (size_t i = 0; i < rp_state->createInfo.attachmentCount; ++i) {
9225e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9226127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                auto pAttachment = &rp_state->createInfo.pAttachments[i];
9227bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp, pAttachment->stencilStoreOp,
9228bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VK_ATTACHMENT_STORE_OP_STORE)) {
922958c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
92309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
923158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
923258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
923358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
9234db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp,
9235bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE)) {
923658c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
92379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
923858c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
923958c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
924058c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
92415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
92425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
92435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9244315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass()", VALIDATION_ERROR_1b000017);
9245315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass()", VALIDATION_ERROR_1b000019);
9246315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdEndRenderPass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1b002415);
92473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()");
92481ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_ENDRENDERPASS);
92490e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    }
92500e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    lock.unlock();
92510e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
92523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
92530e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
92544a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdEndRenderPass(commandBuffer);
92550e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
92560e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    if (pCB) {
92570e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes        lock.lock();
925855867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        TransitionFinalSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, framebuffer);
925958c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeRenderPass = nullptr;
926058c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeSubpass = 0;
926158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeFramebuffer = VK_NULL_HANDLE;
92625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
92645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9265a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, uint32_t primaryAttach,
9266a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                        uint32_t secondaryAttach, const char *msg) {
9267df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9268315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                   HandleToUint64(secondaryBuffer), __LINE__, VALIDATION_ERROR_1b2000c4, "DS",
9269df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "vkCmdExecuteCommands() called w/ invalid Secondary Cmd Buffer 0x%" PRIx64
9270df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   " which has a render pass "
9271df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "that is not compatible with the Primary Cmd Buffer current render pass. "
9272df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "Attachment %u is not compatible with %u: %s. %s",
92739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                   HandleToUint64(secondaryBuffer), primaryAttach, secondaryAttach, msg,
9274315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                   validation_error_map[VALIDATION_ERROR_1b2000c4]);
92755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
92765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9277a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9278a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, uint32_t primaryAttach,
9279a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkCommandBuffer secondaryBuffer, VkRenderPassCreateInfo const *secondaryPassCI,
9280e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                            uint32_t secondaryAttach, bool is_multi) {
92813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9282a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->attachmentCount <= primaryAttach) {
92835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primaryAttach = VK_ATTACHMENT_UNUSED;
92845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9285a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (secondaryPassCI->attachmentCount <= secondaryAttach) {
92865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondaryAttach = VK_ATTACHMENT_UNUSED;
92875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) {
92893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
92905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED) {
92923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
92933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "The first is unused while the second is not.");
92943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
92955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondaryAttach == VK_ATTACHMENT_UNUSED) {
92973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
92983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "The second is unused while the first is not.");
92993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
93005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9301a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].format != secondaryPassCI->pAttachments[secondaryAttach].format) {
93023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9303a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different formats.");
93045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9305a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].samples != secondaryPassCI->pAttachments[secondaryAttach].samples) {
93063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9307a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different samples.");
93085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9309a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (is_multi && primaryPassCI->pAttachments[primaryAttach].flags != secondaryPassCI->pAttachments[secondaryAttach].flags) {
93103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9311a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different flags.");
93125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
93145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9316a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9317a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9318a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *secondaryPassCI, const int subpass, bool is_multi) {
93193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9320a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &primary_desc = primaryPassCI->pSubpasses[subpass];
9321a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &secondary_desc = secondaryPassCI->pSubpasses[subpass];
93225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
93235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) {
93245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
93255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.inputAttachmentCount) {
93265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_input_attach = primary_desc.pInputAttachments[i].attachment;
93275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.inputAttachmentCount) {
93295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
93305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_input_attach, secondaryBuffer,
93323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_input_attach, is_multi);
93335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
93355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) {
93365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
93375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount) {
93385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_color_attach = primary_desc.pColorAttachments[i].attachment;
93395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount) {
93415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
93425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_color_attach, secondaryBuffer,
93443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_color_attach, is_multi);
93455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
93465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
93475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
93485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
93505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
93515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_resolve_attach, secondaryBuffer,
93533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_resolve_attach, is_multi);
93545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
93565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primary_desc.pDepthStencilAttachment) {
93575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
93585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_desc.pDepthStencilAttachment) {
93605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
93615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_depthstencil_attach, secondaryBuffer,
93633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            secondaryPassCI, secondary_depthstencil_attach, is_multi);
93643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
93655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9367a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// Verify that given renderPass CreateInfo for primary and secondary command buffers are compatible.
9368a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  This function deals directly with the CreateInfo, there are overloaded versions below that can take the renderPass handle and
9369a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  will then feed into this function
9370a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9371a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9372a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *secondaryPassCI) {
93733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9374a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis
9375a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->subpassCount != secondaryPassCI->subpassCount) {
93763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
93779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(primaryBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
93783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer 0x%" PRIx64
93793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        " that has a subpassCount of %u that is incompatible with the primary Cmd Buffer 0x%" PRIx64
93803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        " that has a subpassCount of %u.",
93819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(secondaryBuffer), secondaryPassCI->subpassCount, HandleToUint64(primaryBuffer),
93829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        primaryPassCI->subpassCount);
9383a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    } else {
9384a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        for (uint32_t i = 0; i < primaryPassCI->subpassCount; ++i) {
93853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateSubpassCompatibility(dev_data, primaryBuffer, primaryPassCI, secondaryBuffer, secondaryPassCI, i,
93863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                 primaryPassCI->subpassCount > 1);
9387a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
93885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
93905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9392e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
9393e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) {
93943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
93955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pSubCB->beginInfo.pInheritanceInfo) {
93963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
93975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9398c5b97dda856ff837638b3ebb7e231d5507c495a3Chris Forbes    VkFramebuffer primary_fb = pCB->activeFramebuffer;
93995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
94005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_fb != VK_NULL_HANDLE) {
94015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (primary_fb != secondary_fb) {
94023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9403315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(primaryBuffer), __LINE__, VALIDATION_ERROR_1b2000c6, "DS",
94043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdExecuteCommands() called w/ invalid secondary command buffer 0x%" PRIx64
94053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " which has a framebuffer 0x%" PRIx64
94063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " that is not the same as the primary command buffer's current active framebuffer 0x%" PRIx64 ". %s",
94079b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(secondaryBuffer), HandleToUint64(secondary_fb), HandleToUint64(primary_fb),
9408315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1b2000c6]);
94095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto fb = GetFramebufferState(dev_data, secondary_fb);
9411e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes        if (!fb) {
94123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
94139b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(primaryBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
94143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
94153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "which has invalid framebuffer 0x%" PRIx64 ".",
94169b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            (void *)secondaryBuffer, HandleToUint64(secondary_fb));
94173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            return skip;
94185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_renderpass = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
9420a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if (cb_renderpass->renderPass != fb->createInfo.renderPass) {
94213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb->renderPassCreateInfo.ptr(), secondaryBuffer,
94223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                    cb_renderpass->createInfo.ptr());
9423a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
94245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
94265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9428e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
94293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
94305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<int> activeTypes;
94315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pCB->activeQueries) {
94325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
94335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end()) {
94345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
94355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pSubCB->beginInfo.pInheritanceInfo) {
94365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
94375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) {
94389b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    skip |= log_msg(
94399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9440315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_1b2000d0, "DS",
94419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
94429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "which has invalid active query pool 0x%" PRIx64
94439b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        ". Pipeline statistics is being queried so the command "
94449b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "buffer must have all bits set on the queryPool. %s",
9445315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        pCB->commandBuffer, HandleToUint64(queryPoolData->first), validation_error_map[VALIDATION_ERROR_1b2000d0]);
94465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
94475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
94485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            activeTypes.insert(queryPoolData->second.createInfo.queryType);
94495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pSubCB->startedQueries) {
94525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
94535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
94549b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
94559b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
94569b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
94579b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "which has invalid active query pool 0x%" PRIx64
94589b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "of type %d but a query of that type has been started on "
94599b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "secondary Cmd Buffer 0x%p.",
94609b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pCB->commandBuffer, HandleToUint64(queryPoolData->first), queryPoolData->second.createInfo.queryType,
94619b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pSubCB->commandBuffer);
94625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94647bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
94659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto primary_pool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
94669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto secondary_pool = GetCommandPoolNode(dev_data, pSubCB->createInfo.commandPool);
94677bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    if (primary_pool && secondary_pool && (primary_pool->queueFamilyIndex != secondary_pool->queueFamilyIndex)) {
94683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9469226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
94709b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(pSubCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_FAMILY, "DS",
9471226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "vkCmdExecuteCommands(): Primary command buffer 0x%p"
9472226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    " created in queue family %d has secondary command buffer 0x%p created in queue family %d.",
9473226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    pCB->commandBuffer, primary_pool->queueFamilyIndex, pSubCB->commandBuffer, secondary_pool->queueFamilyIndex);
94747bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
94757bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
94763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
94775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9479bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
9480bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
94813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
948256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9483b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
94849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
94855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
94865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        GLOBAL_CB_NODE *pSubCB = NULL;
94875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < commandBuffersCount; i++) {
94889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            pSubCB = GetCBNode(dev_data, pCommandBuffers[i]);
94890a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            assert(pSubCB);
94900a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) {
94913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
9492df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9493315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_1b2000b0, "DS",
9494df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "vkCmdExecuteCommands() called w/ Primary Cmd Buffer 0x%p in element %u of pCommandBuffers "
9495df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "array. All cmd buffers in pCommandBuffers array must be secondary. %s",
9496315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCommandBuffers[i], i, validation_error_map[VALIDATION_ERROR_1b2000b0]);
9497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (pCB->activeRenderPass) {  // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
94980de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                if (pSubCB->beginInfo.pInheritanceInfo != nullptr) {
94990de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    auto secondary_rp_state = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
95000de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
95010de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        skip |= log_msg(
95020de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9503315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_1b2000c0, "DS",
95040de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) executed within render pass (0x%" PRIxLEAST64
95050de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT "
95060de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "set. %s",
95070de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            pCommandBuffers[i], HandleToUint64(pCB->activeRenderPass->renderPass),
9508315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1b2000c0]);
95090de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    } else {
95100de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        // Make sure render pass is compatible with parent command buffer pass if has continue
95110de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        if (pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) {
95120de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            skip |=
95130de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                                validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass->createInfo.ptr(),
95143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                                pCommandBuffers[i], secondary_rp_state->createInfo.ptr());
95150de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        }
95160de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        //  If framebuffer for secondary CB is not NULL, then it must match active FB from primaryCB
95170de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        skip |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB);
95180de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    }
95190de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    string errorString = "";
95200de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    // secondaryCB must have been created w/ RP compatible w/ primaryCB active renderpass
95210de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    if ((pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) &&
95220de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(),
95230de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                                                         secondary_rp_state->createInfo.ptr(), errorString)) {
95240de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        skip |= log_msg(
95250de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
95260de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            HandleToUint64(pCommandBuffers[i]), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
95270de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) w/ render pass (0x%" PRIxLEAST64
95280de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            ") is incompatible w/ primary command buffer (0x%p) w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
95290de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            pCommandBuffers[i], HandleToUint64(pSubCB->beginInfo.pInheritanceInfo->renderPass), commandBuffer,
95300de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            HandleToUint64(pCB->activeRenderPass->renderPass), errorString.c_str());
9531a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                    }
95325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
95335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
95345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO(mlentine): Move more logic into this method
95353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB);
9536315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= validateCommandBufferState(dev_data, pSubCB, "vkCmdExecuteCommands()", 0, VALIDATION_ERROR_1b2000b2);
95375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
95389b2582dc67737351a72fbeb82e9e6e8cdff7a026Chris Forbes                if (pSubCB->in_use.load() || pCB->linkedCommandBuffers.count(pSubCB)) {
95393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
95409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCB->commandBuffer), __LINE__,
9541315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    VALIDATION_ERROR_1b2000b4, "DS",
95423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Attempt to simultaneously execute command buffer 0x%p"
95433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set! %s",
9544315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    pCB->commandBuffer, validation_error_map[VALIDATION_ERROR_1b2000b4]);
95455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
95465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
95475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
95483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
95495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
95509b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
9551226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) "
9552226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer "
9553226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "(0x%p) to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
955483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "set, even though it does.",
9555226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], pCB->commandBuffer);
95565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
95575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
95585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
9559f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes            if (!pCB->activeQueries.empty() && !dev_data->enabled_features.inheritedQueries) {
95603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
9561cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9562315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_1b2000ca, "DS",
9563cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer "
9564cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "(0x%p) cannot be submitted with a query in "
9565cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "flight and inherited queries not "
9566cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "supported on this device. %s",
9567315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCommandBuffers[i], validation_error_map[VALIDATION_ERROR_1b2000ca]);
95685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
95699b2582dc67737351a72fbeb82e9e6e8cdff7a026Chris Forbes            // TODO: separate validate from update! This is very tangled.
95708567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            // Propagate layout transitions to the primary cmd buffer
95718567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            for (auto ilm_entry : pSubCB->imageLayoutMap) {
957255867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski                SetLayout(dev_data, pCB, ilm_entry.first, ilm_entry.second);
95738567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            }
95745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pSubCB->primaryCommandBuffer = pCB->commandBuffer;
95751a3660584634742a3297915c94768d73f360e794Chris Forbes            pCB->linkedCommandBuffers.insert(pSubCB);
95761a3660584634742a3297915c94768d73f360e794Chris Forbes            pSubCB->linkedCommandBuffers.insert(pCB);
9577d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            for (auto &function : pSubCB->queryUpdates) {
9578d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine                pCB->queryUpdates.push_back(function);
9579d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            }
95805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9581315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteCommands()", VALIDATION_ERROR_1b200019);
9582315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
9583315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdExecuteCommands()",
9584315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_1b202415);
9585f5a52627a6576d3d532cd1f2e1be6d9987aeda7fChris Forbes        skip |= ValidateCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteCommands()");
95861ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_EXECUTECOMMANDS);
95875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9588b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
95893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
95905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9592bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
9593bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         void **ppData) {
959456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
95955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
95963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
95975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
9598b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
95999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
9600cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    if (mem_info) {
9601f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        // TODO : This could me more fine-grained to track just region that is valid
9602f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        mem_info->global_valid = true;
9603623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        auto end_offset = (VK_WHOLE_SIZE == size) ? mem_info->alloc_info.allocationSize - 1 : offset + size - 1;
96043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateMapImageLayouts(dev_data, device, mem_info, offset, end_offset);
9605cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        // TODO : Do we need to create new "bound_range" for the mapped range?
9606623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        SetMemRangesValid(dev_data, mem_info, offset, end_offset);
9607cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        if ((dev_data->phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
9608b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
96093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9610315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           HandleToUint64(mem), __LINE__, VALIDATION_ERROR_31200554, "MEM",
96113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj 0x%" PRIxLEAST64 ". %s",
9612315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           HandleToUint64(mem), validation_error_map[VALIDATION_ERROR_31200554]);
96135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateMapMemRange(dev_data, mem, offset, size);
9616b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
96175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
96183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
96194a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.MapMemory(device, mem, offset, size, flags, ppData);
96207c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        if (VK_SUCCESS == result) {
96217c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.lock();
9622cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : What's the point of this range? See comment on creating new "bound_range" above, which may replace this
96237c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            storeMemRanges(dev_data, mem, offset, size);
96245f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            initializeAndTrackMemory(dev_data, mem, offset, size, ppData);
96257c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.unlock();
96267c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        }
96275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
96295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
963189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL UnmapMemory(VkDevice device, VkDeviceMemory mem) {
963256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
96333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
96345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9635b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
96363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= deleteMemRanges(dev_data, mem);
9637b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
96383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
96394a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UnmapMemory(device, mem);
96405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
96438860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool validateMemoryIsMapped(layer_data *dev_data, const char *funcName, uint32_t memRangeCount,
9644e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                   const VkMappedMemoryRange *pMemRanges) {
9645c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    bool skip = false;
96465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < memRangeCount; ++i) {
96479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, pMemRanges[i].memory);
964857fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
9649f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            if (pMemRanges[i].size == VK_WHOLE_SIZE) {
9650f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if (mem_info->mem_range.offset > pMemRanges[i].offset) {
9651315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    skip |=
9652315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9653315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pMemRanges[i].memory), __LINE__, VALIDATION_ERROR_0c20055c, "MEM",
9654315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER
9655315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                ") is less than Memory Object's offset "
9656315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "(" PRINTF_SIZE_T_SPECIFIER "). %s",
9657315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                funcName, static_cast<size_t>(pMemRanges[i].offset),
9658315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                static_cast<size_t>(mem_info->mem_range.offset), validation_error_map[VALIDATION_ERROR_0c20055c]);
9659f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
9660f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            } else {
9661f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                const uint64_t data_end = (mem_info->mem_range.size == VK_WHOLE_SIZE)
9662f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              ? mem_info->alloc_info.allocationSize
9663f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              : (mem_info->mem_range.offset + mem_info->mem_range.size);
9664f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if ((mem_info->mem_range.offset > pMemRanges[i].offset) ||
9665f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                    (data_end < (pMemRanges[i].offset + pMemRanges[i].size))) {
9666c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski                    skip |=
9667f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9668315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pMemRanges[i].memory), __LINE__, VALIDATION_ERROR_0c20055a, "MEM",
9669f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "%s: Flush/Invalidate size or offset (" PRINTF_SIZE_T_SPECIFIER ", " PRINTF_SIZE_T_SPECIFIER
9670f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                ") exceed the Memory Object's upper-bound "
9671f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "(" PRINTF_SIZE_T_SPECIFIER "). %s",
9672f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
9673f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(data_end),
9674315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_0c20055a]);
9675f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
96765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
96775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9679c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    return skip;
96805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9682bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic bool ValidateAndCopyNoncoherentMemoryToDriver(layer_data *dev_data, uint32_t mem_range_count,
9683bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                     const VkMappedMemoryRange *mem_ranges) {
9684bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    bool skip = false;
9685bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
96869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
968757fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
96885f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            if (mem_info->shadow_copy) {
96895f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
96905f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                        ? mem_info->mem_range.size
9691d8a53ade6b5501256798a8b4ec0bc14f72adc1faTobin Ehlis                                        : (mem_info->alloc_info.allocationSize - mem_info->mem_range.offset);
96925f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                char *data = static_cast<char *>(mem_info->shadow_copy);
96935f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = 0; j < mem_info->shadow_pad_size; ++j) {
96945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
96959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        skip |= log_msg(
96969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
96979b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem_ranges[i].memory), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
96989b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Memory underflow was detected on mem obj 0x%" PRIxLEAST64, HandleToUint64(mem_ranges[i].memory));
96995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
97005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
97015f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = (size + mem_info->shadow_pad_size); j < (2 * mem_info->shadow_pad_size + size); ++j) {
97025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
97039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        skip |= log_msg(
97049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
97059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem_ranges[i].memory), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
97069b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Memory overflow was detected on mem obj 0x%" PRIxLEAST64, HandleToUint64(mem_ranges[i].memory));
97075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
97085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
97095f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                memcpy(mem_info->p_driver_data, static_cast<void *>(data + mem_info->shadow_pad_size), (size_t)(size));
97105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
97115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9713bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    return skip;
97145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9716bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic void CopyNoncoherentMemoryFromDriver(layer_data *dev_data, uint32_t mem_range_count, const VkMappedMemoryRange *mem_ranges) {
9717bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
97189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
97195f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info && mem_info->shadow_copy) {
97205f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
97215f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    ? mem_info->mem_range.size
97225f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    : (mem_info->alloc_info.allocationSize - mem_ranges[i].offset);
97235f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            char *data = static_cast<char *>(mem_info->shadow_copy);
97245f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            memcpy(data + mem_info->shadow_pad_size, mem_info->p_driver_data, (size_t)(size));
97259e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski        }
97269e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski    }
97279e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski}
97289e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski
9729ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinskistatic bool ValidateMappedMemoryRangeDeviceLimits(layer_data *dev_data, const char *func_name, uint32_t mem_range_count,
9730ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                                                  const VkMappedMemoryRange *mem_ranges) {
9731ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    bool skip = false;
9732ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
9733ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        uint64_t atom_size = dev_data->phys_dev_properties.properties.limits.nonCoherentAtomSize;
973416769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(mem_ranges[i].offset, atom_size) != 0) {
9735df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9736315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(mem_ranges->memory), __LINE__, VALIDATION_ERROR_0c20055e, "MEM",
9737ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Offset in pMemRanges[%d] is 0x%" PRIxLEAST64
9738ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
9739315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            func_name, i, mem_ranges[i].offset, atom_size, validation_error_map[VALIDATION_ERROR_0c20055e]);
9740ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
974116769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if ((mem_ranges[i].size != VK_WHOLE_SIZE) && (SafeModulo(mem_ranges[i].size, atom_size) != 0)) {
9742df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9743315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(mem_ranges->memory), __LINE__, VALIDATION_ERROR_0c200560, "MEM",
9744ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Size in pMemRanges[%d] is 0x%" PRIxLEAST64
9745ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
9746315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            func_name, i, mem_ranges[i].size, atom_size, validation_error_map[VALIDATION_ERROR_0c200560]);
9747ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
9748ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    }
9749ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    return skip;
9750ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski}
9751ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski
975280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateFlushMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
975380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                   const VkMappedMemoryRange *mem_ranges) {
975480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
975580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
975680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= ValidateAndCopyNoncoherentMemoryToDriver(dev_data, mem_range_count, mem_ranges);
975780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkFlushMappedMemoryRanges", mem_range_count, mem_ranges);
975880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
975980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
976080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
9761bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
9762bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                       const VkMappedMemoryRange *pMemRanges) {
97635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
976456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
97655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
976680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateFlushMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
97674a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
97685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
97705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
977280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
977380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                        const VkMappedMemoryRange *mem_ranges) {
977480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
977580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
977680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkInvalidateMappedMemoryRanges", mem_range_count, mem_ranges);
977780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
977880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
977980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
978080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic void PostCallRecordInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
978180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                       const VkMappedMemoryRange *mem_ranges) {
978280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
978380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    // Update our shadow copy with modified driver data
978480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    CopyNoncoherentMemoryFromDriver(dev_data, mem_range_count, mem_ranges);
978580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
978680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
9787bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL InvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
9788bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                            const VkMappedMemoryRange *pMemRanges) {
97895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
979056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
97915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
979280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
97934a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
979480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        if (result == VK_SUCCESS) {
979580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski            PostCallRecordInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges);
979680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        }
97975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
97995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9801160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic bool PreCallValidateBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
9802160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                           VkDeviceSize memoryOffset) {
98030109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski    bool skip = false;
98041facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
9805160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
980694c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        // Track objects tied to memory
98079b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t image_handle = HandleToUint64(image);
98087a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip = ValidateSetMemBinding(dev_data, mem, image_handle, kVulkanObjectTypeImage, "vkBindImageMemory()");
9809ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        if (!image_state->memory_requirements_checked) {
9810ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // There's not an explicit requirement in the spec to call vkGetImageMemoryRequirements() prior to calling
9811341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // BindImageMemory but it's implied in that memory being bound must conform with VkMemoryRequirements from
9812341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // vkGetImageMemoryRequirements()
98130109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
98140109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle, __LINE__, DRAWSTATE_INVALID_IMAGE, "DS",
98150109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            "vkBindImageMemory(): Binding memory to image 0x%" PRIxLEAST64
98160109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            " but vkGetImageMemoryRequirements() has not been called on that image.",
98170109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle);
9818ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // Make the call for them so we can verify the state
9819ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.unlock();
9820341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            dev_data->dispatch_table.GetImageMemoryRequirements(dev_data->device, image, &image_state->requirements);
9821ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.lock();
9822ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        }
982347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
98240ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Validate bound memory range information
98259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
982657fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
98270ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= ValidateInsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
98280ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                                   image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR, "vkBindImageMemory()");
982974300755ed9ec780d6073af71e47f201217008d6Cort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, image_state->requirements.memoryTypeBits, "vkBindImageMemory()",
9830315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        VALIDATION_ERROR_1740082e);
983147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
9832160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
9833160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements alignment
983416769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(memoryOffset, image_state->requirements.alignment) != 0) {
9835160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
9836315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            image_handle, __LINE__, VALIDATION_ERROR_17400830, "DS",
9837160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindImageMemory(): memoryOffset is 0x%" PRIxLEAST64
9838160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be an integer multiple of the "
9839160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
9840160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
9841315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            memoryOffset, image_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_17400830]);
9842160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
9843160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
9844160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements size
9845160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        if (image_state->requirements.size > mem_info->alloc_info.allocationSize - memoryOffset) {
9846160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
9847315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            image_handle, __LINE__, VALIDATION_ERROR_17400832, "DS",
9848160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindImageMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
9849160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be at least as large as "
9850160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
9851160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
9852160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            mem_info->alloc_info.allocationSize - memoryOffset, image_state->requirements.size,
9853315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_17400832]);
9854160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
9855341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
9856341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    return skip;
9857341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
985847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
9859160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic void PostCallRecordBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
9860160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                          VkDeviceSize memoryOffset) {
9861341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (image_state) {
9862160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
98630ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Track bound memory range information
98640ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto mem_info = GetMemObjInfo(dev_data, mem);
98650ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        if (mem_info) {
98660ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            InsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
98670ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                   image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR);
98680ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
98690ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
9870c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
98719b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t image_handle = HandleToUint64(image);
98727a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        SetMemBinding(dev_data, mem, image_handle, kVulkanObjectTypeImage, "vkBindImageMemory()");
9873c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
9874341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.mem = mem;
9875341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.offset = memoryOffset;
9876341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.size = image_state->requirements.size;
9877341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
9878341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
9879341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton
9880341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
9881341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
9882341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
9883160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    auto image_state = GetImageState(dev_data, image);
9884160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    bool skip = PreCallValidateBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
9885341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (!skip) {
9886341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        result = dev_data->dispatch_table.BindImageMemory(device, image, mem, memoryOffset);
9887341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        if (result == VK_SUCCESS) {
9888160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            PostCallRecordBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
988994c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        }
98905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
98915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
98925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
989489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL SetEvent(VkDevice device, VkEvent event) {
98953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
98963ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
989756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
9898b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
98999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto event_state = GetEventNode(dev_data, event);
99004710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    if (event_state) {
99014710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->needsSignaled = false;
99024710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->stageMask = VK_PIPELINE_STAGE_HOST_BIT;
99034710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state->write_in_use) {
99043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
99059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(event), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
99063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Cannot call vkSetEvent() on event 0x%" PRIxLEAST64 " that is already in use by a command buffer.",
99079b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(event));
99083ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis        }
99093ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    }
9910b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
99116fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // Host setting event is visible to all queues immediately so update stageMask for any queue that's seen this event
99126fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // TODO : For correctness this needs separate fix to verify that app doesn't make incorrect assumptions about the
99136fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // ordering of this command in relation to vkCmd[Set|Reset]Events (see GH297)
99146fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    for (auto queue_data : dev_data->queueMap) {
99156fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        auto event_entry = queue_data.second.eventToStageMap.find(event);
99166fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        if (event_entry != queue_data.second.eventToStageMap.end()) {
99176fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis            event_entry->second |= VK_PIPELINE_STAGE_HOST_BIT;
99186fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        }
99196fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    }
99203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) result = dev_data->dispatch_table.SetEvent(device, event);
99215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
99225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9924bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
9925bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               VkFence fence) {
992656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
99275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
99283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9929b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
99309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
99319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
9932651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
99334b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    // First verify that fence is not in use
99343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateFenceForSubmit(dev_data, pFence);
9935651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
99369867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence) {
993793ccd9708dad3ffb58a3fc09a3d61cc5fe1569f8Mark Lobodzinski        SubmitFence(pQueue, pFence, std::max(1u, bindInfoCount));
99384b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    }
9939651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
99401344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) {
99411344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx];
99425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Track objects tied to memory
99431344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.bufferBindCount; j++) {
99441344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pBufferBinds[j].bindCount; k++) {
9945f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pBufferBinds[j].pBinds[k];
9946f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
99479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(bindInfo.pBufferBinds[j].buffer), kVulkanObjectTypeBuffer))
99483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
99495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99511344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageOpaqueBindCount; j++) {
99521344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageOpaqueBinds[j].bindCount; k++) {
9953f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageOpaqueBinds[j].pBinds[k];
9954f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
99559b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(bindInfo.pImageOpaqueBinds[j].image), kVulkanObjectTypeImage))
99563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
99575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99591344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageBindCount; j++) {
99601344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageBinds[j].bindCount; k++) {
9961f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageBinds[j].pBinds[k];
9962f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                // TODO: This size is broken for non-opaque bindings, need to update to comprehend full sparse binding data
9963f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                VkDeviceSize size = sparse_binding.extent.depth * sparse_binding.extent.height * sparse_binding.extent.width * 4;
9964f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, size},
99659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(bindInfo.pImageBinds[j].image), kVulkanObjectTypeImage))
99663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
99675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99699867daedbf52debc77d6568162ee21e071699b80Chris Forbes
99709867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<SEMAPHORE_WAIT> semaphore_waits;
99719867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<VkSemaphore> semaphore_signals;
99721344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
997301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pWaitSemaphores[i];
99749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
997501a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
997601a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
99779867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
99789867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
99799867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        pSemaphore->in_use.fetch_add(1);
99809867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
99819867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = VK_NULL_HANDLE;
998201a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                    pSemaphore->signaled = false;
99831344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
99843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
99859b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
99863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkQueueBindSparse: Queue 0x%p is waiting on semaphore 0x%" PRIx64
99873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " that has no way to be signaled.",
99889b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    queue, HandleToUint64(semaphore));
99895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
99905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99921344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
999301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pSignalSemaphores[i];
99949a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
999501a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
999601a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
99973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
99989b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                   HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
99993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                   "vkQueueBindSparse: Queue 0x%p is signaling semaphore 0x%" PRIx64
100003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                   ", but that semaphore is already signaled.",
100019b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                   queue, HandleToUint64(semaphore));
10002bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                } else {
100039867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = queue;
100049867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
100059867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaled = true;
100069867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->in_use.fetch_add(1);
100079867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    semaphore_signals.push_back(semaphore);
100089867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
100095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
100105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
100119867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10012bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), semaphore_waits, semaphore_signals,
100139867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         bindIdx == bindInfoCount - 1 ? fence : VK_NULL_HANDLE);
100145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100159867daedbf52debc77d6568162ee21e071699b80Chris Forbes
100169867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence && !bindInfoCount) {
100179867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // No work to do, just dropping a fence in the queue by itself.
10018bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
100199867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         fence);
100209867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
100219867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10022b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
100235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
100243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) return dev_data->dispatch_table.QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
100255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
100265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1002989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
1003089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
1003156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
100324a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
100335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10034b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10035bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        SEMAPHORE_NODE *sNode = &dev_data->semaphoreMap[*pSemaphore];
100369867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.first = VK_NULL_HANDLE;
100379867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.second = 0;
100381344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        sNode->signaled = false;
100395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10043bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
10044bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
1004556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
100464a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateEvent(device, pCreateInfo, pAllocator, pEvent);
100475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10048b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
100495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].needsSignaled = false;
10050293ecfc5e69ed3978a8c04518166d828294870a4Tony Barbour        dev_data->eventMap[*pEvent].write_in_use = 0;
100515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
100525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
100569ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinskistatic bool PreCallValidateCreateSwapchainKHR(layer_data *dev_data, const char *func_name,
100579ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              VkSwapchainCreateInfoKHR const *pCreateInfo, SURFACE_STATE *surface_state,
100589ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              SWAPCHAIN_NODE *old_swapchain_state) {
10059d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    auto most_recent_swapchain = surface_state->swapchain ? surface_state->swapchain : surface_state->old_swapchain;
10060d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
100614bd5f453535de3d3423ff1f9995b4acb15f791d2Chris Forbes    // TODO: revisit this. some of these rules are being relaxed.
100620bbc015828bdb99e85e6731ce92428557902701fPetr Kraus
100630bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    // All physical devices and queue families are required to be able
100640bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    // to present to any native window on Android; require the
100650bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    // application to have established support on any other platform.
10066d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski    if (!dev_data->instance_data->extensions.vk_khr_android_surface) {
100670bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        auto support_predicate = [dev_data](decltype(surface_state->gpu_queue_support)::const_reference qs) -> bool {
100680bbc015828bdb99e85e6731ce92428557902701fPetr Kraus            // TODO: should restrict search only to queue families of VkDeviceQueueCreateInfos, not whole phys. device
100690bbc015828bdb99e85e6731ce92428557902701fPetr Kraus            return (qs.first.gpu == dev_data->physical_device) && qs.second;
100700bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        };
100710bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        const auto& support = surface_state->gpu_queue_support;
100720bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        bool is_supported = std::any_of(support.begin(), support.end(), support_predicate);
100730bbc015828bdb99e85e6731ce92428557902701fPetr Kraus
100740bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        if (!is_supported) {
100750bbc015828bdb99e85e6731ce92428557902701fPetr Kraus            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10076315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009ec, "DS",
100770bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                        "%s: pCreateInfo->surface is not known at this time to be supported for presentation by this device. "
100780bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                        "The vkGetPhysicalDeviceSurfaceSupportKHR() must be called beforehand, and it must return VK_TRUE support "
100790bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                        "with this surface for at least one queue family of this device. %s",
10080315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        func_name, validation_error_map[VALIDATION_ERROR_146009ec]))
100810bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                return true;
100820bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        }
100830bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    }
100840bbc015828bdb99e85e6731ce92428557902701fPetr Kraus
10085d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (most_recent_swapchain != old_swapchain_state || (surface_state->old_swapchain && surface_state->swapchain)) {
10086d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
100879b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_ALREADY_EXISTS, "DS",
100889ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface has an existing swapchain other than oldSwapchain", func_name))
10089d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10090d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
10091d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (old_swapchain_state && old_swapchain_state->createInfo.surface != pCreateInfo->surface) {
10092d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
100939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(pCreateInfo->oldSwapchain), __LINE__, DRAWSTATE_SWAPCHAIN_WRONG_SURFACE, "DS",
100949b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    "%s: pCreateInfo->oldSwapchain's surface is not pCreateInfo->surface", func_name))
10095d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10096d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
100979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
100987de258f87ca1192db116a66b209253793d276ebcChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState == UNCALLED) {
100997de258f87ca1192db116a66b209253793d276ebcChris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
101009b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(dev_data->physical_device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
101019ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface capabilities not retrieved for this physical device", func_name))
101027de258f87ca1192db116a66b209253793d276ebcChris Forbes            return true;
10103cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // have valid capabilities
101045c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        auto &capabilities = physical_device_state->surfaceCapabilities;
101059ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->minImageCount against VkSurfaceCapabilitiesKHR::{min|max}ImageCount:
101062fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if (pCreateInfo->minImageCount < capabilities.minImageCount) {
101072fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10108315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009ee, "DS",
101099ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
101102fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
101119ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
10112315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009ee]))
101132fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                return true;
101142fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        }
101152fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
101162fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if ((capabilities.maxImageCount > 0) && (pCreateInfo->minImageCount > capabilities.maxImageCount)) {
101175c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10118315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f0, "DS",
101199ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
101202fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
101219ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
10122315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f0]))
101235c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
101245c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
101252fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
101269ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageExtent against VkSurfaceCapabilitiesKHR::{current|min|max}ImageExtent:
101272e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width == kSurfaceSizeFromSwapchain) &&
101282e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width < capabilities.minImageExtent.width) ||
101292e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.width > capabilities.maxImageExtent.width) ||
101302e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height < capabilities.minImageExtent.height) ||
101312e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height > capabilities.maxImageExtent.height))) {
101325c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10133315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f4, "DS",
101349ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is outside the bounds returned by "
101359ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (%d,%d), minImageExtent = (%d,%d), "
101369ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "maxImageExtent = (%d,%d). %s",
101379ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
101389ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height, capabilities.minImageExtent.width,
101399ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.minImageExtent.height, capabilities.maxImageExtent.width, capabilities.maxImageExtent.height,
10140315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f4]))
101415c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
101425c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
101439ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->preTransform should have exactly one bit set, and that bit must also be set in
101449ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedTransforms.
101455c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->preTransform || (pCreateInfo->preTransform & (pCreateInfo->preTransform - 1)) ||
101465c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !(pCreateInfo->preTransform & capabilities.supportedTransforms)) {
101479ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
101489ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
101495c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
101505c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
101515c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
101529ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->preTransform (i.e. %s).  Supported values are:\n", func_name,
101535c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    string_VkSurfaceTransformFlagBitsKHR(pCreateInfo->preTransform));
101545c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
101555c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
101565c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
101575c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedTransforms) {
101585c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkSurfaceTransformFlagBitsKHR((VkSurfaceTransformFlagBitsKHR)(1 << i));
101595c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
101605c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
101615c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
101625c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
101635c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
101645c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10165315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009fe, "DS", "%s. %s", errorString.c_str(),
10166315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009fe]))
101675c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
101685c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
101697b0d28d116977b91892f354e002edd760bdb86cbChris Forbes
101709ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->compositeAlpha should have exactly one bit set, and that bit must also be set in
101719ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedCompositeAlpha
101725c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->compositeAlpha || (pCreateInfo->compositeAlpha & (pCreateInfo->compositeAlpha - 1)) ||
101735c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !((pCreateInfo->compositeAlpha) & capabilities.supportedCompositeAlpha)) {
101749ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
101759ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
101765c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
101775c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
101785c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
101799ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->compositeAlpha (i.e. %s).  Supported values are:\n",
101809ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    func_name, string_VkCompositeAlphaFlagBitsKHR(pCreateInfo->compositeAlpha));
101815c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
101825c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
101835c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
101845c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedCompositeAlpha) {
101855c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkCompositeAlphaFlagBitsKHR((VkCompositeAlphaFlagBitsKHR)(1 << i));
101865c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
101875c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
101885c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
101895c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
101905c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
101915c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10192315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_14600a00, "DS", "%s. %s", errorString.c_str(),
10193315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_14600a00]))
101945c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
101955c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
101969ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageArrayLayers against VkSurfaceCapabilitiesKHR::maxImageArrayLayers:
101975c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if ((pCreateInfo->imageArrayLayers < 1) || (pCreateInfo->imageArrayLayers > capabilities.maxImageArrayLayers)) {
101985c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10199315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f6, "DS",
102009ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported imageArrayLayers (i.e. %d).  Minimum value is 1, maximum value is %d. %s",
102019ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageArrayLayers, capabilities.maxImageArrayLayers,
10202315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f6]))
102035c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
102045c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
102059ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageUsage against VkSurfaceCapabilitiesKHR::supportedUsageFlags:
102065c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (pCreateInfo->imageUsage != (pCreateInfo->imageUsage & capabilities.supportedUsageFlags)) {
102075c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10208315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f8, "DS",
102099ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported pCreateInfo->imageUsage (i.e. 0x%08x).  Supported flag bits are 0x%08x. %s",
102109ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageUsage, capabilities.supportedUsageFlags,
10211315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f8]))
102125c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
102135c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
102147de258f87ca1192db116a66b209253793d276ebcChris Forbes    }
10215d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
102169ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfaceFormatsKHR():
102175faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState != QUERY_DETAILS) {
102185faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
102199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
102209ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s called before calling vkGetPhysicalDeviceSurfaceFormatsKHR().", func_name))
102215faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            return true;
102225faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    } else {
102239ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageFormat against VkSurfaceFormatKHR::format:
102245faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundFormat = false;
102255faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundColorSpace = false;
102265faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundMatch = false;
102275faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        for (auto const &format : physical_device_state->surface_formats) {
102285faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (pCreateInfo->imageFormat == format.format) {
102299ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                // Validate pCreateInfo->imageColorSpace against VkSurfaceFormatKHR::colorSpace:
102305faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                foundFormat = true;
102315faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
102325faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundMatch = true;
102335faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    break;
102345faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
102355faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            } else {
102365faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
102375faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundColorSpace = true;
102385faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
102395faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
102405faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
102415faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (!foundMatch) {
102425faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (!foundFormat) {
102435faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10244315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f2, "DS",
10245bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageFormat (i.e. %d). %s", func_name,
10246315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCreateInfo->imageFormat, validation_error_map[VALIDATION_ERROR_146009f2]))
102472fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                    return true;
102482fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            }
102492fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (!foundColorSpace) {
102502fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10251315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f2, "DS",
10252bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageColorSpace (i.e. %d). %s", func_name,
10253315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCreateInfo->imageColorSpace, validation_error_map[VALIDATION_ERROR_146009f2]))
102545faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    return true;
102555faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
102565faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
102575faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
102585faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
102599ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfacePresentModesKHR():
102609e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState != QUERY_DETAILS) {
1026125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // FIFO is required to always be supported
102629e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pCreateInfo->presentMode != VK_PRESENT_MODE_FIFO_KHR) {
102639e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
102649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
102659ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called before calling vkGetPhysicalDeviceSurfacePresentModesKHR().", func_name))
102669e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
102679e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
102689e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    } else {
102699ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->presentMode against vkGetPhysicalDeviceSurfacePresentModesKHR():
10270bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        bool foundMatch = std::find(physical_device_state->present_modes.begin(), physical_device_state->present_modes.end(),
102719e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                    pCreateInfo->presentMode) != physical_device_state->present_modes.end();
102729e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (!foundMatch) {
102739e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10274315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_14600a02, "DS",
102759ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported presentMode (i.e. %s). %s", func_name,
10276315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        string_VkPresentModeKHR(pCreateInfo->presentMode), validation_error_map[VALIDATION_ERROR_14600a02]))
102779e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
102789e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
102799e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
1028087a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis    // Validate state for shared presentable case
1028187a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis    if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfo->presentMode ||
1028287a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfo->presentMode) {
10283a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski        if (!dev_data->extensions.vk_khr_shared_presentable_image) {
1028487a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10285480a11822ef9a45f577f13644759c0895a49db19Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_EXTENSION_NOT_ENABLED, "DS",
102866084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        "%s called with presentMode %s which requires the VK_KHR_shared_presentable_image extension, which has not "
102876084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        "been enabled.",
102886084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        func_name, string_VkPresentModeKHR(pCreateInfo->presentMode)))
102896084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                return true;
102906084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski        } else if (pCreateInfo->minImageCount != 1) {
102916084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10292315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_14600ace, "DS",
1029387a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                        "%s called with presentMode %s, but minImageCount value is %d. For shared presentable image, minImageCount "
102946084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        "must be 1. %s",
102956084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        func_name, string_VkPresentModeKHR(pCreateInfo->presentMode), pCreateInfo->minImageCount,
10296315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_14600ace]))
1029787a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                return true;
1029887a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        }
1029987a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis    }
103009e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
10301d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    return false;
10302d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes}
10303d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
10304261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinskistatic void PostCallRecordCreateSwapchainKHR(layer_data *dev_data, VkResult result, const VkSwapchainCreateInfoKHR *pCreateInfo,
10305261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             VkSwapchainKHR *pSwapchain, SURFACE_STATE *surface_state,
10306261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             SWAPCHAIN_NODE *old_swapchain_state) {
103075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
10308b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10309ddc5201048319558ce66701163a4546ee957af19Chris Forbes        auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(pCreateInfo, *pSwapchain));
1031087a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfo->presentMode ||
1031187a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfo->presentMode) {
1031287a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            swapchain_state->shared_presentable = true;
1031387a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        }
10314ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = swapchain_state.get();
1031516a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes        dev_data->swapchainMap[*pSwapchain] = std::move(swapchain_state);
10316ddc5201048319558ce66701163a4546ee957af19Chris Forbes    } else {
10317ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = nullptr;
103185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10319ddc5201048319558ce66701163a4546ee957af19Chris Forbes    // Spec requires that even if CreateSwapchainKHR fails, oldSwapchain behaves as replaced.
103205b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    if (old_swapchain_state) {
103215b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes        old_swapchain_state->replaced = true;
103225b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    }
10323ddc5201048319558ce66701163a4546ee957af19Chris Forbes    surface_state->old_swapchain = old_swapchain_state;
10324261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    return;
10325261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski}
10326261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10327261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
10328261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
1032956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
103309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(dev_data->instance_data, pCreateInfo->surface);
103319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto old_swapchain_state = GetSwapchainNode(dev_data, pCreateInfo->oldSwapchain);
10332261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
103339ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    if (PreCallValidateCreateSwapchainKHR(dev_data, "vkCreateSwapChainKHR()", pCreateInfo, surface_state, old_swapchain_state)) {
10334261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10335261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    }
10336261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10337261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    VkResult result = dev_data->dispatch_table.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
10338261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10339261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    PostCallRecordCreateSwapchainKHR(dev_data, result, pCreateInfo, pSwapchain, surface_state, old_swapchain_state);
10340ddc5201048319558ce66701163a4546ee957af19Chris Forbes
103415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
103425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
103435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10344bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
1034556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
103463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
103475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10348b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
103499a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
10350b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swapchain_data) {
10351b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_data->images.size() > 0) {
10352b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis            for (auto swapchain_image : swapchain_data->images) {
103535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
103545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (image_sub != dev_data->imageSubresourceMap.end()) {
103555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    for (auto imgsubpair : image_sub->second) {
103565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
103575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if (image_item != dev_data->imageLayoutMap.end()) {
103585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            dev_data->imageLayoutMap.erase(image_item);
103595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
103605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
103615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    dev_data->imageSubresourceMap.erase(image_sub);
103625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
103639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip = ClearMemoryObjectBindings(dev_data, HandleToUint64(swapchain_image), kVulkanObjectTypeSwapchainKHR);
1036494c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                dev_data->imageMap.erase(swapchain_image);
103655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
103665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10367ddc5201048319558ce66701163a4546ee957af19Chris Forbes
103689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
10369ddc5201048319558ce66701163a4546ee957af19Chris Forbes        if (surface_state) {
10370cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->swapchain == swapchain_data) surface_state->swapchain = nullptr;
10371cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->old_swapchain == swapchain_data) surface_state->old_swapchain = nullptr;
10372ddc5201048319558ce66701163a4546ee957af19Chris Forbes        }
10373ddc5201048319558ce66701163a4546ee957af19Chris Forbes
1037416a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes        dev_data->swapchainMap.erase(swapchain);
103755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10376b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
103773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
103785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
103795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10380bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount,
10381bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                     VkImage *pSwapchainImages) {
1038256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
103834a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
103845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10385ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pSwapchainImages != nullptr) {
103865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This should never happen and is checked by param checker.
10387cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!pCount) return result;
10388b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
103899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_node = GetSwapchainNode(dev_data, swapchain);
10390ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes
10391ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes        if (*pCount > swapchain_node->images.size())
10392ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes            swapchain_node->images.resize(*pCount);
10393ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes
103945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < *pCount; ++i) {
10395ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes            if (swapchain_node->images[i] != VK_NULL_HANDLE)
10396ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes                continue;   // Already retrieved this.
10397ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes
103985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            IMAGE_LAYOUT_NODE image_layout_node;
103995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
104005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.format = swapchain_node->createInfo.imageFormat;
104016d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            // Add imageMap entries for each swapchain image
104026d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            VkImageCreateInfo image_ci = {};
10403eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.flags = 0;
10404eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.imageType = VK_IMAGE_TYPE_2D;
104056d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.format = swapchain_node->createInfo.imageFormat;
104066d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.width = swapchain_node->createInfo.imageExtent.width;
104076d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.height = swapchain_node->createInfo.imageExtent.height;
10408d1a9776c1a22ec99a3ef0dd44e7f85a78a04d1edTony Barbour            image_ci.extent.depth = 1;
10409eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.mipLevels = 1;
10410eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.arrayLayers = swapchain_node->createInfo.imageArrayLayers;
10411eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
10412eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
10413eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.usage = swapchain_node->createInfo.imageUsage;
104146d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.sharingMode = swapchain_node->createInfo.imageSharingMode;
104151facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            dev_data->imageMap[pSwapchainImages[i]] = unique_ptr<IMAGE_STATE>(new IMAGE_STATE(pSwapchainImages[i], &image_ci));
104161facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto &image_state = dev_data->imageMap[pSwapchainImages[i]];
104171facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->valid = false;
10418e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            image_state->binding.mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
10419ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes            swapchain_node->images[i] = pSwapchainImages[i];
104205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
104215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
104225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageLayoutMap[subpair] = image_layout_node;
104235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
104245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
104255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
104265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
104275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1042889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
1042956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
104303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
104315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
104326c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    std::lock_guard<std::mutex> lock(global_lock);
104339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
104341671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
104356c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
104369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
104376c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        if (pSemaphore && !pSemaphore->signaled) {
104383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
104393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
104403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
104419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPresentInfo->pWaitSemaphores[i]));
104425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
104436c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
10444249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
104456c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
104469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10447a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes        if (swapchain_data) {
10448a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes            if (pPresentInfo->pImageIndices[i] >= swapchain_data->images.size()) {
104499b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |=
104509b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
104519b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
104529b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "vkQueuePresentKHR: Swapchain image index too large (%u). There are only %u images in this swapchain.",
104539b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pPresentInfo->pImageIndices[i], (uint32_t)swapchain_data->images.size());
10454bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            } else {
10455a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
104569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, image);
1045787a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis
1045887a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                if (image_state->shared_presentable) {
1045987a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                    image_state->layout_locked = true;
1046087a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                }
10461c4f799ed5502f05ce97543e0500b4a19dc5f2461Mark Lobodzinski
104623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateImageMemoryIsValid(dev_data, image_state, "vkQueuePresentKHR()");
10463a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
104641facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                if (!image_state->acquired) {
104653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
10466bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
104679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_IMAGE_NOT_ACQUIRED, "DS",
10468bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        "vkQueuePresentKHR: Swapchain image index %u has not been acquired.", pPresentInfo->pImageIndices[i]);
10469a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                }
10470a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
10471a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                vector<VkImageLayout> layouts;
10472a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                if (FindLayouts(dev_data, image, layouts)) {
10473a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                    for (auto layout : layouts) {
104746084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        if ((layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) &&
10475a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski                            (!dev_data->extensions.vk_khr_shared_presentable_image ||
104766084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                             (layout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR))) {
104773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |=
104782fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
10479315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        HandleToUint64(queue), __LINE__, VALIDATION_ERROR_11200a20, "DS",
104802fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "Images passed to present must be in layout "
104816084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                                        "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR or VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR but is in %s. %s",
10482315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        string_VkImageLayout(layout), validation_error_map[VALIDATION_ERROR_11200a20]);
10483a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        }
104845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
104855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
104865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
104871671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
104881671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // All physical devices and queue families are required to be able
104891671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // to present to any native window on Android; require the
104901671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // application to have established support on any other platform.
10491d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski            if (!dev_data->instance_data->extensions.vk_khr_android_surface) {
104929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
104931671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                auto support_it = surface_state->gpu_queue_support.find({dev_data->physical_device, queue_state->queueFamilyIndex});
104941671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
104951671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                if (support_it == surface_state->gpu_queue_support.end()) {
104963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |=
104971671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
104989b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_UNSUPPORTED_QUEUE, "DS",
10499cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkQueuePresentKHR: Presenting image without calling "
10500cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkGetPhysicalDeviceSurfaceSupportKHR");
105011671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                } else if (!support_it->second) {
105029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    skip |=
105039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10504315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, VALIDATION_ERROR_31800a18, "DS",
105059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkQueuePresentKHR: Presenting image on queue that cannot "
105069b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "present to this surface. %s",
10507315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_31800a18]);
105081671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                }
105091671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            }
105105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
105115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10512c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis    if (pPresentInfo && pPresentInfo->pNext) {
10513c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        // Verify ext struct
10514c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        struct std_header {
10515c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            VkStructureType sType;
10516c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            const void *pNext;
10517c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        };
10518c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        std_header *pnext = (std_header *)pPresentInfo->pNext;
10519c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        while (pnext) {
10520c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            if (VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR == pnext->sType) {
10521c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                VkPresentRegionsKHR *present_regions = (VkPresentRegionsKHR *)pnext;
10522c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
10523c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10524c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    assert(swapchain_data);
10525c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    VkPresentRegionKHR region = present_regions->pRegions[i];
10526c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    for (uint32_t j = 0; j < region.rectangleCount; ++j) {
10527c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        VkRectLayerKHR rect = region.pRectangles[j];
10528c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        // TODO: Need to update these errors to their unique error ids when available
10529c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if ((rect.offset.x + rect.extent.width) > swapchain_data->createInfo.imageExtent.width) {
105309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            skip |= log_msg(
105319b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
105329b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
105339b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
105349b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "chain, pRegion[%i].pRectangles[%i], the sum of offset.x "
105359b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "(%i) and extent.width (%i) is greater than the "
105369b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "corresponding swapchain's imageExtent.width (%i).",
105379b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                i, j, rect.offset.x, rect.extent.width, swapchain_data->createInfo.imageExtent.width);
10538c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
10539c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if ((rect.offset.y + rect.extent.height) > swapchain_data->createInfo.imageExtent.height) {
105409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            skip |= log_msg(
105419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
105429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
105439b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
105449b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "chain, pRegion[%i].pRectangles[%i], the sum of offset.y "
105459b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "(%i) and extent.height (%i) is greater than the "
105469b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "corresponding swapchain's imageExtent.height (%i).",
105479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                i, j, rect.offset.y, rect.extent.height, swapchain_data->createInfo.imageExtent.height);
10548c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
10549c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if (rect.layer > swapchain_data->createInfo.imageArrayLayers) {
105503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |= log_msg(
10551c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
105529b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
10553c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, pRegion[%i].pRectangles[%i], the "
10554c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                "layer (%i) is greater than the corresponding swapchain's imageArrayLayers (%i).",
10555c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                i, j, rect.layer, swapchain_data->createInfo.imageArrayLayers);
10556c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
10557c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    }
10558c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                }
105595f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis            } else if (VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE == pnext->sType) {
105605f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                VkPresentTimesInfoGOOGLE *present_times_info = (VkPresentTimesInfoGOOGLE *)pnext;
105615f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                if (pPresentInfo->swapchainCount != present_times_info->swapchainCount) {
105625f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                    skip |=
105635f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
105649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[0]), __LINE__,
105655f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis
10566315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                VALIDATION_ERROR_118009be, "DS",
105675f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "vkQueuePresentKHR(): VkPresentTimesInfoGOOGLE.swapchainCount is %i but "
105685f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "pPresentInfo->swapchainCount is %i. For VkPresentTimesInfoGOOGLE down pNext "
105695f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "chain of VkPresentInfoKHR, VkPresentTimesInfoGOOGLE.swapchainCount "
105705f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "must equal VkPresentInfoKHR.swapchainCount.",
105715f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                present_times_info->swapchainCount, pPresentInfo->swapchainCount);
105725f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                }
10573c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            }
10574c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            pnext = (std_header *)pnext->pNext;
10575c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        }
10576c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis    }
105775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
105783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
105796c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
105806c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
105816c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
105824a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueuePresentKHR(queue, pPresentInfo);
105836c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
105846c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (result != VK_ERROR_VALIDATION_FAILED_EXT) {
105856c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // Semaphore waits occur before error generation, if the call reached
105866c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // the ICD. (Confirm?)
105876c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
105889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
105899867daedbf52debc77d6568162ee21e071699b80Chris Forbes            if (pSemaphore) {
105909867daedbf52debc77d6568162ee21e071699b80Chris Forbes                pSemaphore->signaler.first = VK_NULL_HANDLE;
105916c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes                pSemaphore->signaled = false;
105926c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes            }
105936c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        }
105949867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10595220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
10596220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Note: this is imperfect, in that we can get confused about what
10597220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // did or didn't succeed-- but if the app does that, it's confused
10598220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // itself just as much.
10599220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto local_result = pPresentInfo->pResults ? pPresentInfo->pResults[i] : result;
10600220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10601cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (local_result != VK_SUCCESS && local_result != VK_SUBOPTIMAL_KHR) continue;  // this present didn't actually happen.
10602220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10603220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Mark the image as having been released to the WSI
106049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10605220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
106069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_state = GetImageState(dev_data, image);
106071facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->acquired = false;
10608220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        }
10609220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
106109867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // Note: even though presentation is directed to a queue, there is no
106119867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // direct ordering between QP and subsequent work, so QP (and its
106129867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // semaphore waits) /never/ participate in any completion proof.
106136c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
106141344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
106155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
106165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
106175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10618c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic bool PreCallValidateCreateSharedSwapchainsKHR(layer_data *dev_data, uint32_t swapchainCount,
10619c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10620c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SURFACE_STATE *> &surface_state,
10621c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
106220342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (pCreateInfos) {
10623c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
106240342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
106259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            surface_state.push_back(GetSurfaceState(dev_data->instance_data, pCreateInfos[i].surface));
106269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            old_swapchain_state.push_back(GetSwapchainNode(dev_data, pCreateInfos[i].oldSwapchain));
106279ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            std::stringstream func_name;
106289ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            func_name << "vkCreateSharedSwapchainsKHR[" << swapchainCount << "]";
10629bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (PreCallValidateCreateSwapchainKHR(dev_data, func_name.str().c_str(), &pCreateInfos[i], surface_state[i],
10630bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  old_swapchain_state[i])) {
10631c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                return true;
106320342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            }
106330342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
106340342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10635c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return false;
10636c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
106370342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10638c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic void PostCallRecordCreateSharedSwapchainsKHR(layer_data *dev_data, VkResult result, uint32_t swapchainCount,
10639c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10640c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SURFACE_STATE *> &surface_state,
10641c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
106420342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (VK_SUCCESS == result) {
106430342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
106440342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(&pCreateInfos[i], pSwapchains[i]));
1064587a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfos[i].presentMode ||
1064687a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfos[i].presentMode) {
1064787a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                swapchain_state->shared_presentable = true;
1064887a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            }
106490342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = swapchain_state.get();
1065016a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes            dev_data->swapchainMap[pSwapchains[i]] = std::move(swapchain_state);
106510342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
106520342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    } else {
106530342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
106540342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = nullptr;
106550342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
106560342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
106570342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    // Spec requires that even if CreateSharedSwapchainKHR fails, oldSwapchain behaves as replaced.
106580342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    for (uint32_t i = 0; i < swapchainCount; i++) {
106590342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        if (old_swapchain_state[i]) {
106600342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            old_swapchain_state[i]->replaced = true;
106610342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
106620342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        surface_state[i]->old_swapchain = old_swapchain_state[i];
106630342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10664c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return;
10665c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
10666c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10667c6cd632d064579a64e61d8704b411d0e4ace7adaMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
10668c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkSwapchainCreateInfoKHR *pCreateInfos,
10669c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
1067056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10671c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SURFACE_STATE *> surface_state;
10672c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SWAPCHAIN_NODE *> old_swapchain_state;
10673c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10674c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    if (PreCallValidateCreateSharedSwapchainsKHR(dev_data, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10675c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                 old_swapchain_state)) {
10676c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10677c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    }
10678c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10679c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    VkResult result =
10680c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        dev_data->dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
10681c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10682c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    PostCallRecordCreateSharedSwapchainsKHR(dev_data, result, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10683c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                            old_swapchain_state);
106840342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10685c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    return result;
10686c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young}
10687c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1068889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
1068989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
1069056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
106913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
106921344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
10693b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
10694449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
10695449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    if (fence == VK_NULL_HANDLE && semaphore == VK_NULL_HANDLE) {
106963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
106979b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(device), __LINE__, DRAWSTATE_SWAPCHAIN_NO_SYNC_FOR_ACQUIRE, "DS",
106983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: Semaphore and fence cannot both be VK_NULL_HANDLE. There would be no way "
106993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "to determine the completion of this operation.");
10700449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    }
10701449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
107029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
10703f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pSemaphore && pSemaphore->signaled) {
107043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
10705315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(semaphore), __LINE__, VALIDATION_ERROR_16400a0c, "DS",
107063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state. %s",
10707315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_16400a0c]);
107085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10709f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
107109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
10711f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pFence) {
107123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateFenceForSubmit(dev_data, pFence);
107135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
107144a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes
107159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
10716fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
10717fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    if (swapchain_data->replaced) {
107183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
107199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_REPLACED, "DS",
107203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: This swapchain has been replaced. The application can still "
107213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "present any images it has acquired, but cannot acquire any more.");
10722fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    }
10723fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
107249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
107254a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState != UNCALLED) {
107266569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        uint64_t acquired_images = std::count_if(swapchain_data->images.begin(), swapchain_data->images.end(),
107279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                 [=](VkImage image) { return GetImageState(dev_data, image)->acquired; });
107284a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        if (acquired_images > swapchain_data->images.size() - physical_device_state->surfaceCapabilities.minImageCount) {
107293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
107306569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
107319b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_TOO_MANY_IMAGES, "DS",
107326569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        "vkAcquireNextImageKHR: Application has already acquired the maximum number of images (0x%" PRIxLEAST64 ")",
107336569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        acquired_images);
107344a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        }
107354a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    }
1073675269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
1073775269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    if (swapchain_data->images.size() == 0) {
107383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
107399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_IMAGES_NOT_FOUND, "DS",
107403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: No images found to acquire from. Application probably did not call "
107413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkGetSwapchainImagesKHR after swapchain creation.");
1074275269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    }
1074375269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
10744b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
107451344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
107463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
10747f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
107484a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
10749f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
10750f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.lock();
10751f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
10752f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pFence) {
10753f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pFence->state = FENCE_INFLIGHT;
10754cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            pFence->signaler.first = VK_NULL_HANDLE;  // ANI isn't on a queue, so this can't participate in a completion proof.
10755f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
10756f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
10757f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        // A successful call to AcquireNextImageKHR counts as a signal operation on semaphore
10758f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pSemaphore) {
10759f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pSemaphore->signaled = true;
107609867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pSemaphore->signaler.first = VK_NULL_HANDLE;
10761f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
10762220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10763220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        // Mark the image as acquired.
10764220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        auto image = swapchain_data->images[*pImageIndex];
107659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, image);
107661facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->acquired = true;
1076787a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        image_state->shared_presentable = swapchain_data->shared_presentable;
107685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10769f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.unlock();
107701344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
107715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
107725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
107735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10774f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
10775f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski                                                        VkPhysicalDevice *pPhysicalDevices) {
107763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1077756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
10778bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    assert(instance_data);
10779219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
10780bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    // For this instance, flag when vkEnumeratePhysicalDevices goes to QUERY_COUNT and then QUERY_DETAILS
10781bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
10782bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_COUNT;
10783f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    } else {
10784bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        if (UNCALLED == instance_data->vkEnumeratePhysicalDevicesState) {
10785bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Flag warning here. You can call this without having queried the count, but it may not be
10786bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // robust on platforms with multiple physical devices.
107873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
107883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
107893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call sequence has vkEnumeratePhysicalDevices() w/ non-NULL pPhysicalDevices. You should first "
107903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "call vkEnumeratePhysicalDevices() w/ NULL pPhysicalDevices to query pPhysicalDeviceCount.");
10791cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }  // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
10792bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        else if (instance_data->physical_devices_count != *pPhysicalDeviceCount) {
10793bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Having actual count match count from app is not a requirement, so this can be a warning
107943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
107953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
107963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call to vkEnumeratePhysicalDevices() w/ pPhysicalDeviceCount value %u, but actual count "
107973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "supported by this instance is %u.",
107983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            *pPhysicalDeviceCount, instance_data->physical_devices_count);
10799bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
10800bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_DETAILS;
10801f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
108023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
10803bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
10804bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
10805bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    VkResult result = instance_data->dispatch_table.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
10806bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
10807bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->physical_devices_count = *pPhysicalDeviceCount;
10808cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (result == VK_SUCCESS) {  // Save physical devices
10809bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
10810bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            auto &phys_device_state = instance_data->physical_device_map[pPhysicalDevices[i]];
10811bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            phys_device_state.phys_device = pPhysicalDevices[i];
10812bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Init actual features for each physical device
10813bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            instance_data->dispatch_table.GetPhysicalDeviceFeatures(pPhysicalDevices[i], &phys_device_state.features);
10814bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
10815bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
10816bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    return result;
10817f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
10818f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
1081943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to handle validation for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1082043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
1082143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 PHYSICAL_DEVICE_STATE *pd_state,
108225770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                 uint32_t requested_queue_family_property_count, bool qfp_null,
108235770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                 const char *caller_name) {
1082443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = false;
108255770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (!qfp_null) {
108265770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        // Verify that for each physical device, this command is called first with NULL pQueueFamilyProperties in order to get count
1082743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
108285770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            skip |= log_msg(
108295770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
108309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(pd_state->phys_device), __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
108315770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "%s is called with non-NULL pQueueFamilyProperties before obtaining pQueueFamilyPropertyCount. It is recommended "
108325770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "to first call %s with NULL pQueueFamilyProperties in order to obtain the maximal pQueueFamilyPropertyCount.",
108335770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                caller_name, caller_name);
108345770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            // Then verify that pCount that is passed in on second call matches what was returned
108355770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        } else if (pd_state->queue_family_count != requested_queue_family_property_count) {
108365770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            skip |= log_msg(
108375770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
108389b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(pd_state->phys_device), __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
108395770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "%s is called with non-NULL pQueueFamilyProperties and pQueueFamilyPropertyCount value %" PRIu32
108405770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                ", but the largest previously returned pQueueFamilyPropertyCount for this physicalDevice is %" PRIu32
108415770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                ". It is recommended to instead receive all the properties by calling %s with pQueueFamilyPropertyCount that was "
108425770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "previously obtained by calling %s with NULL pQueueFamilyProperties.",
108435770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                caller_name, requested_queue_family_property_count, pd_state->queue_family_count, caller_name, caller_name);
1084443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1084543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_DETAILS;
1084643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
108475770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
1084843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return skip;
1084943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1085043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1085143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
108525770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                  PHYSICAL_DEVICE_STATE *pd_state,
108535770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                  uint32_t *pQueueFamilyPropertyCount,
1085443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
108555770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, *pQueueFamilyPropertyCount,
108565770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                (nullptr == pQueueFamilyProperties),
1085743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties()");
1085843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1085943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1086043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_layer_data *instance_data,
1086143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      PHYSICAL_DEVICE_STATE *pd_state,
1086243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1086343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
108645770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, *pQueueFamilyPropertyCount,
108655770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                (nullptr == pQueueFamilyProperties),
1086643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties2KHR()");
1086743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1086843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1086943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to update state for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1087043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1087143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                    VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1087243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (!pQueueFamilyProperties) {
108735770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        if (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState)
108745770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_COUNT;
108755770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->queue_family_count = count;
1087643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } else {  // Save queue family properties
108775770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_DETAILS;
108785770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->queue_family_count = std::max(pd_state->queue_family_count, count);
108795770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
108805770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->queue_family_properties.resize(std::max(static_cast<uint32_t>(pd_state->queue_family_properties.size()), count));
108815770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        for (uint32_t i = 0; i < count; ++i) {
1088243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            pd_state->queue_family_properties[i] = pQueueFamilyProperties[i].queueFamilyProperties;
1088343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1088443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1088543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1088643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1088743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1088843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 VkQueueFamilyProperties *pQueueFamilyProperties) {
1088943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    VkQueueFamilyProperties2KHR *pqfp = nullptr;
1089043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    std::vector<VkQueueFamilyProperties2KHR> qfp;
1089143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    qfp.resize(count);
1089243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (pQueueFamilyProperties) {
1089343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        for (uint32_t i = 0; i < count; ++i) {
1089443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
1089543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].pNext = nullptr;
1089643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].queueFamilyProperties = pQueueFamilyProperties[i];
1089743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1089843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pqfp = qfp.data();
1089943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1090043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pqfp);
1090143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1090243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1090343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1090443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                     VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1090543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pQueueFamilyProperties);
1090643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1090743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
109085770f8ad21c40b2475201e73e9368a899b6886d0Petr KrausVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
109095770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                  uint32_t *pQueueFamilyPropertyCount,
10910bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
1091156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
109129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1091343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
109145770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::unique_lock<std::mutex> lock(global_lock);
109155770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109165770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_data, physical_device_state,
109175770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                      pQueueFamilyPropertyCount, pQueueFamilyProperties);
109185770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109195770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.unlock();
109205770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109215770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (skip) return;
109225770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109235770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount,
109245770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                         pQueueFamilyProperties);
109255770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109265770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.lock();
109275770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    PostCallRecordGetPhysicalDeviceQueueFamilyProperties(physical_device_state, *pQueueFamilyPropertyCount, pQueueFamilyProperties);
1092843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1092943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1093043947a6175e3e942e04d902f4d18928168e2d0dbTobin EhlisVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
1093143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1093243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1093356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
109349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1093543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
109365770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::unique_lock<std::mutex> lock(global_lock);
109375770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
1093843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_data, physical_device_state,
1093943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                          pQueueFamilyPropertyCount, pQueueFamilyProperties);
109405770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109415770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.unlock();
109425770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109435770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (skip) return;
109445770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
1094543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount,
1094643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                             pQueueFamilyProperties);
109475770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109485770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.lock();
1094943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(physical_device_state, *pQueueFamilyPropertyCount,
1095043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                             pQueueFamilyProperties);
10951cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski}
10952cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski
10953bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskitemplate <typename TCreateInfo, typename FPtr>
10954bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkResult CreateSurface(VkInstance instance, TCreateInfo const *pCreateInfo, VkAllocationCallbacks const *pAllocator,
10955bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                              VkSurfaceKHR *pSurface, FPtr fptr) {
1095656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
10957747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
10958747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    // Call down the call chain:
10959747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    VkResult result = (instance_data->dispatch_table.*fptr)(instance, pCreateInfo, pAllocator, pSurface);
10960747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
10961747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (result == VK_SUCCESS) {
10962747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        std::unique_lock<std::mutex> lock(global_lock);
10963747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map[*pSurface] = SURFACE_STATE(*pSurface);
10964747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        lock.unlock();
10965747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
10966747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
10967747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return result;
10968747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
10969747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
10970747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {
109713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1097256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
10973747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
109749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
10975747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
10976747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (surface_state) {
10977747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // TODO: track swapchains created from this surface.
10978747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map.erase(surface);
10979747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
10980747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    lock.unlock();
10981747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
109823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
10983747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // Call down the call chain:
10984747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->dispatch_table.DestroySurfaceKHR(instance, surface, pAllocator);
10985747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
10986747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
10987747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
109886f2ed666809272002a31b3b4f8adf6581cb41819Norbert NopperVKAPI_ATTR VkResult VKAPI_CALL CreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
109896f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper                                                            const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
109906f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateDisplayPlaneSurfaceKHR);
109916f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper}
109926f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper
10993747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
10994747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo,
10995747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
10996747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateAndroidSurfaceKHR);
10997747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
10998cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
10999747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11000747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
11001747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateMirSurfaceKHR(VkInstance instance, const VkMirSurfaceCreateInfoKHR *pCreateInfo,
11002747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11003747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateMirSurfaceKHR);
11004747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11005f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11006f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceMirPresentationSupportKHR(VkPhysicalDevice physicalDevice,
11007f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                          uint32_t queueFamilyIndex, MirConnection *connection) {
11008f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
11009f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11010f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11011f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
11012f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11013f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11014315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2d2009e2,
11015f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceMirPresentationSupportKHR", "queueFamilyIndex");
11016f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11017f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
11018f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11019f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
11020f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11021f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
11022f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result =
11023f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        instance_data->dispatch_table.GetPhysicalDeviceMirPresentationSupportKHR(physicalDevice, queueFamilyIndex, connection);
11024f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11025f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
11026f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
11027cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
11028747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11029747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
11030747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
11031747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11032a9c6cc532ce0ef61d48d1419a96aae51b0e4c64aTobin Ehlis    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWaylandSurfaceKHR);
11033747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11034f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11035f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice,
11036f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                              uint32_t queueFamilyIndex,
11037f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                              struct wl_display *display) {
11038f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
11039f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11040f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11041f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
11042f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11043f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11044315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f000a34,
11045f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceWaylandPresentationSupportKHR", "queueFamilyIndex");
11046f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11047f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
11048f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11049f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
11050f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11051f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
11052f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result =
11053f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        instance_data->dispatch_table.GetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, display);
11054f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11055f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
11056f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
11057cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
11058747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11059747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
11060747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
11061747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11062747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWin32SurfaceKHR);
11063747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11064f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11065f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,
11066f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                            uint32_t queueFamilyIndex) {
11067f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
11068f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11069f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11070f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
11071f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11072f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11073315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f200a3a,
11074f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceWin32PresentationSupportKHR", "queueFamilyIndex");
11075f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11076f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
11077f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11078f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
11079f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11080f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
11081f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result = instance_data->dispatch_table.GetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
11082f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11083f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
11084f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
11085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
11086747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11087747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
11088747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
11089747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11090747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXcbSurfaceKHR);
11091747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11092f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11093f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice,
11094f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                          uint32_t queueFamilyIndex, xcb_connection_t *connection,
11095f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                          xcb_visualid_t visual_id) {
11096f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
11097f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11098f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11099f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
11100f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11101f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11102315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f400a40,
11103f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceXcbPresentationSupportKHR", "queueFamilyIndex");
11104f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11105f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
11106f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11107f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
11108f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11109f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
11110f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result = instance_data->dispatch_table.GetPhysicalDeviceXcbPresentationSupportKHR(physicalDevice, queueFamilyIndex,
11111f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                                               connection, visual_id);
11112f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11113f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
11114f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
11115cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
11116747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11117747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
11118747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
11119bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11120747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXlibSurfaceKHR);
11121747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11122f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11123f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice,
11124f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                           uint32_t queueFamilyIndex, Display *dpy,
11125f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                           VisualID visualID) {
11126f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
11127f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11128f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11129f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
11130f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11131f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11132315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f600a46,
11133f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceXlibPresentationSupportKHR", "queueFamilyIndex");
11134f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11135f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
11136f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11137f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
11138f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11139f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
11140f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result =
11141f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        instance_data->dispatch_table.GetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, dpy, visualID);
11142f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11143f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
11144f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
11145cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
11146747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
1114740921785005eb449ec7c18229f0d84c879708b8aChris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
1114840921785005eb449ec7c18229f0d84c879708b8aChris Forbes                                                                       VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
1114956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1115040921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1115140921785005eb449ec7c18229f0d84c879708b8aChris Forbes    std::unique_lock<std::mutex> lock(global_lock);
111529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1115340921785005eb449ec7c18229f0d84c879708b8aChris Forbes    lock.unlock();
1115440921785005eb449ec7c18229f0d84c879708b8aChris Forbes
11155bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11156bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
1115740921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1115840921785005eb449ec7c18229f0d84c879708b8aChris Forbes    if (result == VK_SUCCESS) {
1115940921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
1116040921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->surfaceCapabilities = *pSurfaceCapabilities;
1116140921785005eb449ec7c18229f0d84c879708b8aChris Forbes    }
1116240921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1116340921785005eb449ec7c18229f0d84c879708b8aChris Forbes    return result;
1116440921785005eb449ec7c18229f0d84c879708b8aChris Forbes}
1116540921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1116635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardtstatic void PostCallRecordGetPhysicalDeviceSurfaceCapabilities2KHR(instance_layer_data *instanceData,
1116735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkPhysicalDevice physicalDevice,
1116835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkSurfaceCapabilities2KHR *pSurfaceCapabilities) {
1116935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    std::unique_lock<std::mutex> lock(global_lock);
1117035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
1117135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
1117235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities = pSurfaceCapabilities->surfaceCapabilities;
1117335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1117435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1117535b630211642e709485879a2e8859736f0ab16a0Mike SchuchardtVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice,
1117635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                        const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
1117735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                        VkSurfaceCapabilities2KHR *pSurfaceCapabilities) {
1117835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1117935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1118035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto result =
1118135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        instanceData->dispatch_table.GetPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, pSurfaceInfo, pSurfaceCapabilities);
1118235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1118335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (result == VK_SUCCESS) {
1118435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        PostCallRecordGetPhysicalDeviceSurfaceCapabilities2KHR(instanceData, physicalDevice, pSurfaceCapabilities);
1118535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
1118635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1118735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    return result;
1118835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1118935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1119035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardtstatic void PostCallRecordGetPhysicalDeviceSurfaceCapabilities2EXT(instance_layer_data *instanceData,
1119135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkPhysicalDevice physicalDevice,
1119235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
1119335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    std::unique_lock<std::mutex> lock(global_lock);
1119435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
1119535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
1119635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.minImageCount = pSurfaceCapabilities->minImageCount;
1119735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.maxImageCount = pSurfaceCapabilities->maxImageCount;
1119835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.currentExtent = pSurfaceCapabilities->currentExtent;
1119935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.minImageExtent = pSurfaceCapabilities->minImageExtent;
1120035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.maxImageExtent = pSurfaceCapabilities->maxImageExtent;
1120135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.maxImageArrayLayers = pSurfaceCapabilities->maxImageArrayLayers;
1120235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.supportedTransforms = pSurfaceCapabilities->supportedTransforms;
1120335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.currentTransform = pSurfaceCapabilities->currentTransform;
1120435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.supportedCompositeAlpha = pSurfaceCapabilities->supportedCompositeAlpha;
1120535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.supportedUsageFlags = pSurfaceCapabilities->supportedUsageFlags;
1120635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1120735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1120835b630211642e709485879a2e8859736f0ab16a0Mike SchuchardtVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
1120935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                        VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
1121035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1121135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1121235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto result =
1121335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        instanceData->dispatch_table.GetPhysicalDeviceSurfaceCapabilities2EXT(physicalDevice, surface, pSurfaceCapabilities);
1121435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1121535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (result == VK_SUCCESS) {
1121635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        PostCallRecordGetPhysicalDeviceSurfaceCapabilities2EXT(instanceData, physicalDevice, pSurfaceCapabilities);
1121735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
1121835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1121935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    return result;
1122035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1122135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
11222418a8711f3301f3027a900bb45daaf0892f4e644Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
11223418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes                                                                  VkSurfaceKHR surface, VkBool32 *pSupported) {
11224f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
1122556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11226f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11227418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
11228f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
112299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
11230f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11231315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2ee009ea,
11232f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceSurfaceSupportKHR", "queueFamilyIndex");
11233f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11234418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    lock.unlock();
11235418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11236f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
11237f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11238bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11239bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
11240418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11241418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    if (result == VK_SUCCESS) {
112420bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        surface_state->gpu_queue_support[{physicalDevice, queueFamilyIndex}] = (*pSupported == VK_TRUE);
11243418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    }
11244418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11245418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    return result;
11246418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes}
11247418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
112489e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
112499e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       uint32_t *pPresentModeCount,
112509e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       VkPresentModeKHR *pPresentModes) {
112513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1125256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
112539e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
112549e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    // TODO: this isn't quite right. available modes may differ by surface AND physical device.
112559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11256bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState;
112579e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112589e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (pPresentModes) {
112599e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        // Compare the preliminary value of *pPresentModeCount with the value this time:
11260bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_mode_count = (uint32_t)physical_device_state->present_modes.size();
112619e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        switch (call_state) {
11262cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
112633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
11264bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
112659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11266cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with non-NULL pPresentModeCount; but no prior positive "
11267cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pPresentModeCount.");
11268cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11269cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11270cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // both query count and query details
11271cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (*pPresentModeCount != prev_mode_count) {
112723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
112739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice), __LINE__,
112749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    DEVLIMITS_COUNT_MISMATCH, "DL",
112753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with *pPresentModeCount (%u) that "
112763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "differs from the value "
112773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "(%u) that was returned when pPresentModes was NULL.",
112783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    *pPresentModeCount, prev_mode_count);
11279cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11280cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
112819e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112829e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
112839e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    lock.unlock();
112849e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
112869e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11287bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount,
11288bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                        pPresentModes);
112899e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112909e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
112919e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        lock.lock();
112929e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112939e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (*pPresentModeCount) {
11294cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
112959e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (*pPresentModeCount > physical_device_state->present_modes.size())
112969e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes.resize(*pPresentModeCount);
112979e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112989e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pPresentModes) {
11299cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
113009e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            for (uint32_t i = 0; i < *pPresentModeCount; i++) {
113019e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes[i] = pPresentModes[i];
113029e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            }
113039e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
113045faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
113055faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113065faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    return result;
113075faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes}
113085faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113095faa662f6859b01c72d79027abde363d5f10dcd7Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
113105faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  uint32_t *pSurfaceFormatCount,
113115faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  VkSurfaceFormatKHR *pSurfaceFormats) {
113123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1131356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
113145faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
113159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11316bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState;
113175faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113185faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (pSurfaceFormats) {
11319bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_format_count = (uint32_t)physical_device_state->surface_formats.size();
113205faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113215faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        switch (call_state) {
11322cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
11323cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Since we haven't recorded a preliminary value of *pSurfaceFormatCount, that likely means that the application
11324cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // didn't
11325cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // previously call this function with a NULL value of pSurfaceFormats:
113263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
11327bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
113289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11329cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount; but no prior positive "
11330cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pSurfaceFormats.");
11331cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11332cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11333cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (prev_format_count != *pSurfaceFormatCount) {
113343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
11335cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
113369b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice), __LINE__,
11337cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        DEVLIMITS_COUNT_MISMATCH, "DL",
11338cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount, and with pSurfaceFormats "
11339cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "set "
11340cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "to "
11341cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "a value (%u) that is greater than the value (%u) that was returned when pSurfaceFormatCount was NULL.",
11342cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        *pSurfaceFormatCount, prev_format_count);
11343cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11344cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
113459e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
113469e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
113475faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    lock.unlock();
113485faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
113509e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
113515faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    // Call down the call chain:
113525faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount,
113535faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                                   pSurfaceFormats);
113545faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113555faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
113565faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        lock.lock();
113575faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113585faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (*pSurfaceFormatCount) {
11359cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
113605faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (*pSurfaceFormatCount > physical_device_state->surface_formats.size())
113615faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats.resize(*pSurfaceFormatCount);
113625faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
113635faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (pSurfaceFormats) {
11364cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
113655faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
113665faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats[i] = pSurfaceFormats[i];
113675faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
113685faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
113695faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
113709e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    return result;
113719e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes}
113729e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
1137335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardtstatic void PostCallRecordGetPhysicalDeviceSurfaceFormats2KHR(instance_layer_data *instanceData, VkPhysicalDevice physicalDevice,
1137435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                              uint32_t *pSurfaceFormatCount, VkSurfaceFormat2KHR *pSurfaceFormats) {
1137535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    std::unique_lock<std::mutex> lock(global_lock);
1137635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
1137735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (*pSurfaceFormatCount) {
1137835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        if (physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState < QUERY_COUNT) {
1137935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState = QUERY_COUNT;
1138035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        }
1138135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        if (*pSurfaceFormatCount > physicalDeviceState->surface_formats.size())
1138235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->surface_formats.resize(*pSurfaceFormatCount);
1138335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
1138435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (pSurfaceFormats) {
1138535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        if (physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState < QUERY_DETAILS) {
1138635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState = QUERY_DETAILS;
1138735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        }
1138835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
1138935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->surface_formats[i] = pSurfaceFormats[i].surfaceFormat;
1139035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        }
1139135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
1139235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1139335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1139435b630211642e709485879a2e8859736f0ab16a0Mike SchuchardtVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice,
1139535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
1139635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   uint32_t *pSurfaceFormatCount,
1139735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkSurfaceFormat2KHR *pSurfaceFormats) {
1139835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1139935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto result = instanceData->dispatch_table.GetPhysicalDeviceSurfaceFormats2KHR(physicalDevice, pSurfaceInfo,
1140035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                                   pSurfaceFormatCount, pSurfaceFormats);
1140135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
1140235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        PostCallRecordGetPhysicalDeviceSurfaceFormats2KHR(instanceData, physicalDevice, pSurfaceFormatCount, pSurfaceFormats);
1140335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
1140435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    return result;
1140535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1140635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
11407bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
11408bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
11409bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkAllocationCallbacks *pAllocator,
11410bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            VkDebugReportCallbackEXT *pMsgCallback) {
1141156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
114129172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkResult res = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
114135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == res) {
11414b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
114158860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        res = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
114165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
114175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
114185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11420bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
1142189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                         const VkAllocationCallbacks *pAllocator) {
1142256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
114239172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
11424b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
114258860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_destroy_msg_callback(instance_data->report_data, msgCallback, pAllocator);
114265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11428bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
11429bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
11430bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1143156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
114329172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
114335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11435bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
11436a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11437a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11438a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11439bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11440bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkLayerProperties *pProperties) {
11441a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11442a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11443a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11444bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
11445bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                    VkExtensionProperties *pProperties) {
11446a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
11447a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
11448a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11449a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return VK_ERROR_LAYER_NOT_PRESENT;
11450a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11451a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11452bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
11453bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
11454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
11455a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
11456a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    assert(physicalDevice);
11457a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
1145856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
114599172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
1146008939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1146108939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11462582b6ed09649188d55ed3b6237352caf9f3384a9Mike WeiblenVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDeviceGroupsKHX(
11463582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupPropertiesKHX *pPhysicalDeviceGroupProperties) {
114643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
11465582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11466582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen
11467582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    if (instance_data) {
11468582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        // For this instance, flag when EnumeratePhysicalDeviceGroupsKHX goes to QUERY_COUNT and then QUERY_DETAILS.
11469582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        if (NULL == pPhysicalDeviceGroupProperties) {
11470582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_COUNT;
11471582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        } else {
11472582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            if (UNCALLED == instance_data->vkEnumeratePhysicalDeviceGroupsState) {
11473582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // Flag warning here. You can call this without having queried the count, but it may not be
11474582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // robust on platforms with multiple physical devices.
114753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
114763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
114773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "Call sequence has vkEnumeratePhysicalDeviceGroupsKHX() w/ non-NULL "
114783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "pPhysicalDeviceGroupProperties. You should first "
114793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "call vkEnumeratePhysicalDeviceGroupsKHX() w/ NULL pPhysicalDeviceGroupProperties to query "
114803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "pPhysicalDeviceGroupCount.");
11481582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            } // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
11482582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            else if (instance_data->physical_device_groups_count != *pPhysicalDeviceGroupCount) {
11483582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // Having actual count match count from app is not a requirement, so this can be a warning
114843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
11485582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
114863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
114873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call to vkEnumeratePhysicalDeviceGroupsKHX() w/ pPhysicalDeviceGroupCount value %u, but actual count "
114883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "supported by this instance is %u.",
114893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            *pPhysicalDeviceGroupCount, instance_data->physical_device_groups_count);
11490582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            }
11491582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_DETAILS;
11492582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
114933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        if (skip) {
11494582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            return VK_ERROR_VALIDATION_FAILED_EXT;
11495582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
11496582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        VkResult result = instance_data->dispatch_table.EnumeratePhysicalDeviceGroupsKHX(instance, pPhysicalDeviceGroupCount,
11497582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            pPhysicalDeviceGroupProperties);
11498582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        if (NULL == pPhysicalDeviceGroupProperties) {
11499582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->physical_device_groups_count = *pPhysicalDeviceGroupCount;
11500582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        } else if (result == VK_SUCCESS) { // Save physical devices
11501582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
11502582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                for (uint32_t j = 0; j < pPhysicalDeviceGroupProperties[i].physicalDeviceCount; j++) {
11503582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    VkPhysicalDevice cur_phys_dev = pPhysicalDeviceGroupProperties[i].physicalDevices[j];
11504582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    auto &phys_device_state = instance_data->physical_device_map[cur_phys_dev];
11505582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    phys_device_state.phys_device = cur_phys_dev;
11506582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    // Init actual features for each physical device
11507582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    instance_data->dispatch_table.GetPhysicalDeviceFeatures(cur_phys_dev, &phys_device_state.features);
11508582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                }
11509582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            }
11510582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
11511582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        return result;
11512582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    } else {
11513582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__,
115149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                DEVLIMITS_INVALID_INSTANCE, "DL",
115159b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                "Invalid instance (0x%" PRIxLEAST64 ") passed into vkEnumeratePhysicalDeviceGroupsKHX().",
115169b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(instance));
11517582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    }
11518582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    return VK_ERROR_VALIDATION_FAILED_EXT;
11519582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen}
11520582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen
115216246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorUpdateTemplateKHR(VkDevice device,
115226246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
115236246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 const VkAllocationCallbacks *pAllocator,
115246246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
115256246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
11526a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski    VkResult result =
11527a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski        dev_data->dispatch_table.CreateDescriptorUpdateTemplateKHR(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
115286246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    if (VK_SUCCESS == result) {
115296246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
115306246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        // Shadow template createInfo for later updates
11531a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski        safe_VkDescriptorUpdateTemplateCreateInfoKHR *local_create_info =
11532a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski            new safe_VkDescriptorUpdateTemplateCreateInfoKHR(pCreateInfo);
115336246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info));
115346246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        dev_data->desc_template_map[*pDescriptorUpdateTemplate] = std::move(template_state);
115356246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    }
115366246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    return result;
115376246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
115386246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
115396246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplateKHR(VkDevice device,
115406246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
115416246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              const VkAllocationCallbacks *pAllocator) {
115426246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
115436246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
115446246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->desc_template_map.erase(descriptorUpdateTemplate);
115456246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    lock.unlock();
115466246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);
115476246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
115486246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
1154925f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSetsWithTemplate()
1155025f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinskistatic void PostCallRecordUpdateDescriptorSetWithTemplateKHR(layer_data *device_data, VkDescriptorSet descriptorSet,
1155125f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski                                                             VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
1155225f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski                                                             const void *pData) {
1155367fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    auto const template_map_entry = device_data->desc_template_map.find(descriptorUpdateTemplate);
1155467fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    if (template_map_entry == device_data->desc_template_map.end()) {
1155567fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski        assert(0);
1155667fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    }
1155767fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
1155825f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski    cvdescriptorset::PerformUpdateDescriptorSetsWithTemplateKHR(device_data, descriptorSet, template_map_entry->second, pData);
1155967fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski}
1156067fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
115616246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
115626246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
115636246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              const void *pData) {
1156467fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1156567fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    device_data->dispatch_table.UpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, pData);
1156667fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
1156767fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    PostCallRecordUpdateDescriptorSetWithTemplateKHR(device_data, descriptorSet, descriptorUpdateTemplate, pData);
115686246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
115696246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
115706246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
115716246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                               VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
115726246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                               VkPipelineLayout layout, uint32_t set, const void *pData) {
115736246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
115746246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set, pData);
115756246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
115766246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
115773616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName);
115783616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName);
115793616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName);
115803616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski
115813616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski// Map of all APIs to be intercepted by this layer
115823616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinskistatic const std::unordered_map<std::string, void*> name_to_funcptr_map = {
115833616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetInstanceProcAddr", (void*)GetInstanceProcAddr},
115843616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vk_layerGetPhysicalDeviceProcAddr", (void*)GetPhysicalDeviceProcAddr},
115853616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetDeviceProcAddr", (void*)GetDeviceProcAddr},
115863616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateInstance", (void*)CreateInstance},
115873616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDevice", (void*)CreateDevice},
115883616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumeratePhysicalDevices", (void*)EnumeratePhysicalDevices},
115893616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceQueueFamilyProperties", (void*)GetPhysicalDeviceQueueFamilyProperties},
115903616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyInstance", (void*)DestroyInstance},
115913616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateInstanceLayerProperties", (void*)EnumerateInstanceLayerProperties},
115923616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateDeviceLayerProperties", (void*)EnumerateDeviceLayerProperties},
115933616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateInstanceExtensionProperties", (void*)EnumerateInstanceExtensionProperties},
115943616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateDeviceExtensionProperties", (void*)EnumerateDeviceExtensionProperties},
115953616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDescriptorUpdateTemplateKHR", (void*)CreateDescriptorUpdateTemplateKHR},
115963616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDescriptorUpdateTemplateKHR", (void*)DestroyDescriptorUpdateTemplateKHR},
115973616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkUpdateDescriptorSetWithTemplateKHR", (void*)UpdateDescriptorSetWithTemplateKHR},
115983616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdPushDescriptorSetWithTemplateKHR", (void*)CmdPushDescriptorSetWithTemplateKHR},
115993616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateSwapchainKHR", (void*)CreateSwapchainKHR},
116003616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySwapchainKHR", (void*)DestroySwapchainKHR},
116013616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetSwapchainImagesKHR", (void*)GetSwapchainImagesKHR},
116023616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAcquireNextImageKHR", (void*)AcquireNextImageKHR},
116033616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueuePresentKHR", (void*)QueuePresentKHR},
116043616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueueSubmit", (void*)QueueSubmit},
116053616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkWaitForFences", (void*)WaitForFences},
116063616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetFenceStatus", (void*)GetFenceStatus},
116073616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueueWaitIdle", (void*)QueueWaitIdle},
116083616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDeviceWaitIdle", (void*)DeviceWaitIdle},
116093616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetDeviceQueue", (void*)GetDeviceQueue},
116103616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDevice", (void*)DestroyDevice},
116113616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyFence", (void*)DestroyFence},
116123616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetFences", (void*)ResetFences},
116133616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySemaphore", (void*)DestroySemaphore},
116143616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyEvent", (void*)DestroyEvent},
116153616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyQueryPool", (void*)DestroyQueryPool},
116163616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyBuffer", (void*)DestroyBuffer},
116173616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyBufferView", (void*)DestroyBufferView},
116183616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyImage", (void*)DestroyImage},
116193616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyImageView", (void*)DestroyImageView},
116203616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyShaderModule", (void*)DestroyShaderModule},
116213616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyPipeline", (void*)DestroyPipeline},
116223616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyPipelineLayout", (void*)DestroyPipelineLayout},
116233616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySampler", (void*)DestroySampler},
116243616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDescriptorSetLayout", (void*)DestroyDescriptorSetLayout},
116253616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDescriptorPool", (void*)DestroyDescriptorPool},
116263616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyFramebuffer", (void*)DestroyFramebuffer},
116273616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyRenderPass", (void*)DestroyRenderPass},
116283616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateBuffer", (void*)CreateBuffer},
116293616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateBufferView", (void*)CreateBufferView},
116303616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateImage", (void*)CreateImage},
116313616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateImageView", (void*)CreateImageView},
116323616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateFence", (void*)CreateFence},
116333616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreatePipelineCache", (void*)CreatePipelineCache},
116343616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyPipelineCache", (void*)DestroyPipelineCache},
116353616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPipelineCacheData", (void*)GetPipelineCacheData},
116363616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkMergePipelineCaches", (void*)MergePipelineCaches},
116373616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateGraphicsPipelines", (void*)CreateGraphicsPipelines},
116383616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateComputePipelines", (void*)CreateComputePipelines},
116393616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateSampler", (void*)CreateSampler},
116403616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDescriptorSetLayout", (void*)CreateDescriptorSetLayout},
116413616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreatePipelineLayout", (void*)CreatePipelineLayout},
116423616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDescriptorPool", (void*)CreateDescriptorPool},
116433616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetDescriptorPool", (void*)ResetDescriptorPool},
116443616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAllocateDescriptorSets", (void*)AllocateDescriptorSets},
116453616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFreeDescriptorSets", (void*)FreeDescriptorSets},
116463616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkUpdateDescriptorSets", (void*)UpdateDescriptorSets},
116473616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateCommandPool", (void*)CreateCommandPool},
116483616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyCommandPool", (void*)DestroyCommandPool},
116493616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetCommandPool", (void*)ResetCommandPool},
116503616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateQueryPool", (void*)CreateQueryPool},
116513616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAllocateCommandBuffers", (void*)AllocateCommandBuffers},
116523616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFreeCommandBuffers", (void*)FreeCommandBuffers},
116533616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkBeginCommandBuffer", (void*)BeginCommandBuffer},
116543616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEndCommandBuffer", (void*)EndCommandBuffer},
116553616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetCommandBuffer", (void*)ResetCommandBuffer},
116563616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindPipeline", (void*)CmdBindPipeline},
116573616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetViewport", (void*)CmdSetViewport},
116583616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetScissor", (void*)CmdSetScissor},
116593616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetLineWidth", (void*)CmdSetLineWidth},
116603616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetDepthBias", (void*)CmdSetDepthBias},
116613616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetBlendConstants", (void*)CmdSetBlendConstants},
116623616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetDepthBounds", (void*)CmdSetDepthBounds},
116633616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetStencilCompareMask", (void*)CmdSetStencilCompareMask},
116643616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetStencilWriteMask", (void*)CmdSetStencilWriteMask},
116653616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetStencilReference", (void*)CmdSetStencilReference},
116663616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindDescriptorSets", (void*)CmdBindDescriptorSets},
116673616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindVertexBuffers", (void*)CmdBindVertexBuffers},
116683616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindIndexBuffer", (void*)CmdBindIndexBuffer},
116693616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDraw", (void*)CmdDraw},
116703616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDrawIndexed", (void*)CmdDrawIndexed},
116713616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDrawIndirect", (void*)CmdDrawIndirect},
116723616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDrawIndexedIndirect", (void*)CmdDrawIndexedIndirect},
116733616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDispatch", (void*)CmdDispatch},
116743616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDispatchIndirect", (void*)CmdDispatchIndirect},
116753616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyBuffer", (void*)CmdCopyBuffer},
116763616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyImage", (void*)CmdCopyImage},
116773616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBlitImage", (void*)CmdBlitImage},
116783616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyBufferToImage", (void*)CmdCopyBufferToImage},
116793616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyImageToBuffer", (void*)CmdCopyImageToBuffer},
116803616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdUpdateBuffer", (void*)CmdUpdateBuffer},
116813616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdFillBuffer", (void*)CmdFillBuffer},
116823616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdClearColorImage", (void*)CmdClearColorImage},
116833616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdClearDepthStencilImage", (void*)CmdClearDepthStencilImage},
116843616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdClearAttachments", (void*)CmdClearAttachments},
116853616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdResolveImage", (void*)CmdResolveImage},
116863616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetImageSubresourceLayout", (void*)GetImageSubresourceLayout},
116873616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetEvent", (void*)CmdSetEvent},
116883616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdResetEvent", (void*)CmdResetEvent},
116893616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdWaitEvents", (void*)CmdWaitEvents},
116903616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdPipelineBarrier", (void*)CmdPipelineBarrier},
116913616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBeginQuery", (void*)CmdBeginQuery},
116923616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdEndQuery", (void*)CmdEndQuery},
116933616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdResetQueryPool", (void*)CmdResetQueryPool},
116943616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyQueryPoolResults", (void*)CmdCopyQueryPoolResults},
116953616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdPushConstants", (void*)CmdPushConstants},
116963616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdWriteTimestamp", (void*)CmdWriteTimestamp},
116973616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateFramebuffer", (void*)CreateFramebuffer},
116983616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateShaderModule", (void*)CreateShaderModule},
116993616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateRenderPass", (void*)CreateRenderPass},
117003616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBeginRenderPass", (void*)CmdBeginRenderPass},
117013616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdNextSubpass", (void*)CmdNextSubpass},
117023616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdEndRenderPass", (void*)CmdEndRenderPass},
117033616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdExecuteCommands", (void*)CmdExecuteCommands},
117043616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkSetEvent", (void*)SetEvent},
117053616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkMapMemory", (void*)MapMemory},
117063616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkUnmapMemory", (void*)UnmapMemory},
117073616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFlushMappedMemoryRanges", (void*)FlushMappedMemoryRanges},
117083616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkInvalidateMappedMemoryRanges", (void*)InvalidateMappedMemoryRanges},
117093616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAllocateMemory", (void*)AllocateMemory},
117103616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFreeMemory", (void*)FreeMemory},
117113616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkBindBufferMemory", (void*)BindBufferMemory},
117123616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetBufferMemoryRequirements", (void*)GetBufferMemoryRequirements},
117133616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetImageMemoryRequirements", (void*)GetImageMemoryRequirements},
117143616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetQueryPoolResults", (void*)GetQueryPoolResults},
117153616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkBindImageMemory", (void*)BindImageMemory},
117163616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueueBindSparse", (void*)QueueBindSparse},
117173616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateSemaphore", (void*)CreateSemaphore},
117183616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateEvent", (void*)CreateEvent},
117193616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_ANDROID_KHR
117203616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateAndroidSurfaceKHR", (void*)CreateAndroidSurfaceKHR},
117213616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117223616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_MIR_KHR
117233616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateMirSurfaceKHR", (void*)CreateMirSurfaceKHR},
117243616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceMirPresentationSupportKHR", (void*)GetPhysicalDeviceMirPresentationSupportKHR},
117253616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117263616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_WAYLAND_KHR
117273616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateWaylandSurfaceKHR", (void*)CreateWaylandSurfaceKHR},
117283616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceWaylandPresentationSupportKHR", (void*)GetPhysicalDeviceWaylandPresentationSupportKHR},
117293616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117303616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_WIN32_KHR
117313616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateWin32SurfaceKHR", (void*)CreateWin32SurfaceKHR},
117323616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceWin32PresentationSupportKHR", (void*)GetPhysicalDeviceWin32PresentationSupportKHR},
117333616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117343616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_XCB_KHR
117353616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateXcbSurfaceKHR", (void*)CreateXcbSurfaceKHR},
117363616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceXcbPresentationSupportKHR", (void*)GetPhysicalDeviceXcbPresentationSupportKHR},
117373616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117383616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_XLIB_KHR
117393616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateXlibSurfaceKHR", (void*)CreateXlibSurfaceKHR},
117403616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceXlibPresentationSupportKHR", (void*)GetPhysicalDeviceXlibPresentationSupportKHR},
117413616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117423616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDisplayPlaneSurfaceKHR", (void*)CreateDisplayPlaneSurfaceKHR},
117433616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySurfaceKHR", (void*)DestroySurfaceKHR},
117443616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", (void*)GetPhysicalDeviceSurfaceCapabilitiesKHR},
117453616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceCapabilities2KHR", (void*)GetPhysicalDeviceSurfaceCapabilities2KHR},
117463616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceCapabilities2EXT", (void*)GetPhysicalDeviceSurfaceCapabilities2EXT},
117473616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceSupportKHR", (void*)GetPhysicalDeviceSurfaceSupportKHR},
117483616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfacePresentModesKHR", (void*)GetPhysicalDeviceSurfacePresentModesKHR},
117493616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceFormatsKHR", (void*)GetPhysicalDeviceSurfaceFormatsKHR},
117503616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceFormats2KHR", (void*)GetPhysicalDeviceSurfaceFormats2KHR},
117513616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceQueueFamilyProperties2KHR", (void*)GetPhysicalDeviceQueueFamilyProperties2KHR},
117523616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumeratePhysicalDeviceGroupsKHX", (void*)EnumeratePhysicalDeviceGroupsKHX},
117533616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDebugReportCallbackEXT", (void*)CreateDebugReportCallbackEXT},
117543616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDebugReportCallbackEXT", (void*)DestroyDebugReportCallbackEXT},
117553616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDebugReportMessageEXT", (void*)DebugReportMessageEXT},
117563616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski};
11757b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
117583616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
117593616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    assert(device);
117603616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
117615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
117623616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    // Is API to be intercepted by this layer?
117633616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    const auto &item = name_to_funcptr_map.find(funcName);
117643616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    if (item != name_to_funcptr_map.end()) {
117653616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
117663616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    }
1176709a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
117683616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    auto &table = device_data->dispatch_table;
11769cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetDeviceProcAddr) return nullptr;
117703616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    return table.GetDeviceProcAddr(device, funcName);
117715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
117725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1177389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
117743616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    instance_layer_data *instance_data;
117753616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    // Is API to be intercepted by this layer?
117763616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    const auto &item = name_to_funcptr_map.find(funcName);
117773616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    if (item != name_to_funcptr_map.end()) {
117783616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
117793616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    }
11780b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
117813616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
117824a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = instance_data->dispatch_table;
11783cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetInstanceProcAddr) return nullptr;
117844a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetInstanceProcAddr(instance, funcName);
117855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1178608939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11787b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
11788b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(instance);
1178956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11790b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11791b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    auto &table = instance_data->dispatch_table;
11792cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetPhysicalDeviceProcAddr) return nullptr;
11793b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return table.GetPhysicalDeviceProcAddr(instance, funcName);
11794b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11795b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11796cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski}  // namespace core_validation
11797d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11798d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu// vk_layer_logging.h expects these to be defined
11799d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11800bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance,
11801bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
11802bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkAllocationCallbacks *pAllocator,
11803bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkDebugReportCallbackEXT *pMsgCallback) {
1180489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
11805d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11806d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11807bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
11808bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                           const VkAllocationCallbacks *pAllocator) {
1180989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
11810d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11811d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11812bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
11813bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
11814bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1181589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
11816d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11817d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11818a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu// loader-layer interface v0, just wrappers since there is only a layer
11819d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11820bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
11821bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                      VkExtensionProperties *pProperties) {
11822a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
1182308939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1182408939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11825bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
11826bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                  VkLayerProperties *pProperties) {
11827a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceLayerProperties(pCount, pProperties);
1182808939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1182908939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11830bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11831bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                VkLayerProperties *pProperties) {
11832a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
11833a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
11834a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
11835d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11836d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11837d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
11838d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    const char *pLayerName, uint32_t *pCount,
11839d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    VkExtensionProperties *pProperties) {
11840a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
11841a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
11842a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    return core_validation::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
11843d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11844d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11845d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
1184689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetDeviceProcAddr(dev, funcName);
11847d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11848d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11849d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
1185089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetInstanceProcAddr(instance, funcName);
1185108939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
11852b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11853bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
11854bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                           const char *funcName) {
11855b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return core_validation::GetPhysicalDeviceProcAddr(instance, funcName);
11856b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11857b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11858b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
11859b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct != NULL);
11860b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
11861b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11862b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    // Fill in the function pointers if our version is at least capable of having the structure contain them.
11863b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
11864b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
11865b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
11866b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
11867b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
11868b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11869b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
11870b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        core_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
11871b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
11872b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
11873b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
11874b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11875b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return VK_SUCCESS;
11876b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11877