core_validation.cpp revision e446ad08318228362ef35d73e7a0636075cb3636
14f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes/* Copyright (c) 2015-2017 The Khronos Group Inc.
24f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes * Copyright (c) 2015-2017 Valve Corporation
34f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes * Copyright (c) 2015-2017 LunarG, Inc.
44f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes * Copyright (C) 2015-2017 Google Inc.
55b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
643b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Licensed under the Apache License, Version 2.0 (the "License");
743b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * you may not use this file except in compliance with the License.
843b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * You may obtain a copy of the License at
95b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
1043b53e83705f02245da6ae61e31273866a35b833Jon Ashburn *     http://www.apache.org/licenses/LICENSE-2.0
115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
1243b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Unless required by applicable law or agreed to in writing, software
1343b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * distributed under the License is distributed on an "AS IS" BASIS,
1443b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1543b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * See the License for the specific language governing permissions and
1643b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * limitations under the License.
175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Cody Northrop <cnorthrop@google.com>
195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Michael Lentine <mlentine@google.com>
205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Tobin Ehlis <tobine@google.com>
215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Chia-I Wu <olv@google.com>
225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Chris Forbes <chrisf@ijw.co.nz>
235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Mark Lobodzinski <mark@lunarg.com>
245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Ian Elliott <ianelliott@google.com>
2560cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Dave Houlton <daveh@lunarg.com>
2660cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Dustin Graves <dustin@lunarg.com>
2760cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Jeremy Hayes <jeremy@lunarg.com>
2860cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Jon Ashburn <jon@lunarg.com>
2960cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Karl Schultz <karl@lunarg.com>
3060cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Mark Young <marky@lunarg.com>
3160cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Mike Schuchardt <mikes@lunarg.com>
3260cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Mike Weiblen <mikew@lunarg.com>
3360cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Tony Barbour <tony@LunarG.com>
345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis */
355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Allow use of STL min and max functions in Windows
375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#define NOMINMAX
385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3994c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <SPIRV/spirv.hpp>
4094c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <algorithm>
4194c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <assert.h>
4294c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <iostream>
4394c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <list>
4494c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <map>
45b9e992386a44404152747d66817a733aa127e281Jeremy Hayes#include <mutex>
4694c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <set>
4768d157d34807071526e5d78b3b3b68c5a4c6185fMark Lobodzinski#include <sstream>
485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <stdio.h>
495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <stdlib.h>
505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <string.h>
5194c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <string>
52dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes#include <tuple>
535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_loader_platform.h"
555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_dispatch_table_helper.h"
5668d157d34807071526e5d78b3b3b68c5a4c6185fMark Lobodzinski#include "vk_enum_string_helper.h"
575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined(__GNUC__)
585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#pragma GCC diagnostic ignored "-Wwrite-strings"
595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined(__GNUC__)
615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#pragma GCC diagnostic warning "-Wwrite-strings"
625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "core_validation.h"
64c06c9b88f5f5bcc7033ba41d5547b048fa6015a4Mark Lobodzinski#include "buffer_validation.h"
655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_table.h"
665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_data.h"
675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_extension_utils.h"
685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_utils.h"
69b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes#include "spirv-tools/libspirv.h"
705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined __ANDROID__
725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <android/log.h>
735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "DS", __VA_ARGS__))
745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#else
75cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#define LOGCONSOLE(...)      \
76cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    {                        \
77cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        printf(__VA_ARGS__); \
78cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        printf("\n");        \
79c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
82d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan// This intentionally includes a cpp file
83d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan#include "vk_safe_struct.cpp"
84d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan
85d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wunamespace core_validation {
86d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_map;
885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_set;
890c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::unique_ptr;
900c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::vector;
910c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::string;
920c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::stringstream;
930c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::max;
945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// WSI Image Objects bypass usual Image Object creation methods.  A special Memory
965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Object value will be used to identify them internally.
975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkDeviceMemory MEMTRACKER_SWAP_CHAIN_IMAGE_KEY = (VkDeviceMemory)(-1);
98888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// 2nd special memory handle used to flag object as unbound from memory
99888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisstatic const VkDeviceMemory MEMORY_UNBOUND = VkDeviceMemory(~((uint64_t)(0)) - 1);
100b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
1012e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// A special value of (0xFFFFFFFF, 0xFFFFFFFF) indicates that the surface size will be determined
1022e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// by the extent of a swapchain targeting the surface.
1032e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madillstatic const uint32_t kSurfaceSizeFromSwapchain = 0xFFFFFFFFu;
1042e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill
1055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// fwd decls
1065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module;
1075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
108f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct instance_layer_data {
109d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkInstance instance = VK_NULL_HANDLE;
110d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    debug_report_data *report_data = nullptr;
1115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<VkDebugReportCallbackEXT> logging_callback;
1129172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkLayerInstanceDispatchTable dispatch_table;
1139172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes
114219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CALL_STATE vkEnumeratePhysicalDevicesState = UNCALLED;
115219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    uint32_t physical_devices_count = 0;
116b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    CALL_STATE vkEnumeratePhysicalDeviceGroupsState = UNCALLED;
117b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    uint32_t physical_device_groups_count = 0;
118219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CHECK_DISABLED disabled = {};
119219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
120f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    unordered_map<VkPhysicalDevice, PHYSICAL_DEVICE_STATE> physical_device_map;
121747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    unordered_map<VkSurfaceKHR, SURFACE_STATE> surface_map;
122747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
123747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool surfaceExtensionEnabled = false;
124747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool displayExtensionEnabled = false;
125747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool androidSurfaceExtensionEnabled = false;
126747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool mirSurfaceExtensionEnabled = false;
127747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool waylandSurfaceExtensionEnabled = false;
128747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool win32SurfaceExtensionEnabled = false;
129747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool xcbSurfaceExtensionEnabled = false;
130747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool xlibSurfaceExtensionEnabled = false;
131f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes};
132f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes
133f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct layer_data {
134f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    debug_report_data *report_data = nullptr;
1354a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkLayerDispatchTable dispatch_table;
13694c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis
137d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    devExts device_extensions = {};
138cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    unordered_set<VkQueue> queues;  // All queues under given device
1395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Global set of all cmdBuffers that are inFlight on this device
1405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<VkCommandBuffer> globalInFlightCmdBuffers;
1415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Layer specific data
142d31a44af6da568692a73201825459689c9431867Tobin Ehlis    unordered_map<VkSampler, unique_ptr<SAMPLER_STATE>> samplerMap;
14379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis    unordered_map<VkImageView, unique_ptr<IMAGE_VIEW_STATE>> imageViewMap;
1441facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    unordered_map<VkImage, unique_ptr<IMAGE_STATE>> imageMap;
14539267c0c27b8f032f05a6747eb02d4508247fdc1Tobin Ehlis    unordered_map<VkBufferView, unique_ptr<BUFFER_VIEW_STATE>> bufferViewMap;
1465cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    unordered_map<VkBuffer, unique_ptr<BUFFER_STATE>> bufferMap;
1474c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    unordered_map<VkPipeline, PIPELINE_STATE *> pipelineMap;
1488d6a38de0389036581ada119e548180c614fe0efChris Forbes    unordered_map<VkCommandPool, COMMAND_POOL_NODE> commandPoolMap;
149a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE *> descriptorPoolMap;
150397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis    unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> setMap;
151cb9ce9e05b8e939d3da35c64997c70049877f4feTobin Ehlis    unordered_map<VkDescriptorSetLayout, cvdescriptorset::DescriptorSetLayout *> descriptorSetLayoutMap;
1525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
15357fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    unordered_map<VkDeviceMemory, unique_ptr<DEVICE_MEM_INFO>> memObjMap;
1545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkFence, FENCE_NODE> fenceMap;
15536c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    unordered_map<VkQueue, QUEUE_STATE> queueMap;
1564710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    unordered_map<VkEvent, EVENT_STATE> eventMap;
1575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<QueryObject, bool> queryToStateMap;
1585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
1595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
16072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis    unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap;
161c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    unordered_map<VkFramebuffer, unique_ptr<FRAMEBUFFER_STATE>> frameBufferMap;
1625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap;
1635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
164127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    unordered_map<VkRenderPass, unique_ptr<RENDER_PASS_STATE>> renderPassMap;
165918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes    unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap;
1666246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    unordered_map<VkDescriptorUpdateTemplateKHR, unique_ptr<TEMPLATE_STATE>> desc_template_map;
16707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
168d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkDevice device = VK_NULL_HANDLE;
169ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    VkPhysicalDevice physical_device = VK_NULL_HANDLE;
1705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
171cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    instance_layer_data *instance_data = nullptr;  // from device to enclosing instance
17207a464bd7fec9583f346b8c4b8d43c88d2e9ffa4Chris Forbes
173f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes    VkPhysicalDeviceFeatures enabled_features = {};
1745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Device specific data
175d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    PHYS_DEV_PROPERTIES_NODE phys_dev_properties = {};
176d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkPhysicalDeviceMemoryProperties phys_dev_mem_props = {};
177e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    VkPhysicalDeviceProperties phys_dev_props = {};
1785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
1795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
180b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis// TODO : Do we need to guard access to layer_data_map w/ lock?
181b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlisstatic unordered_map<void *, layer_data *> layer_data_map;
182f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic unordered_map<void *, instance_layer_data *> instance_layer_data_map;
183b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
184b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Youngstatic uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
185b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
186e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wustatic const VkLayerProperties global_layer = {
187f1ea418f193d10a8455cdf47e0eeeeb1f4d8b5bfJon Ashburn    "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
188e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu};
1895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
190cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class TCreateInfo>
191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskivoid ValidateLayerOrdering(const TCreateInfo &createInfo) {
1925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool foundLayer = false;
1935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) {
194e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu        if (!strcmp(createInfo.ppEnabledLayerNames[i], global_layer.layerName)) {
1955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            foundLayer = true;
1965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
1975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This has to be logged to console as we don't have a callback at this point.
1985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) {
199bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.", global_layer.layerName);
2005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Code imported from shader_checker
2055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *);
2065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words
2085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// without the caller needing to care too much about the physical SPIRV module layout.
2095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct spirv_inst_iter {
2105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator zero;
2115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator it;
2125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
213b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t len() {
214b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        auto result = *it >> 16;
215b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(result > 0);
216b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return result;
217b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
218b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t opcode() { return *it & 0x0ffffu; }
220b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
221b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t const &word(unsigned n) {
222b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(n < len());
223b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return it[n];
224b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
225b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset() { return (uint32_t)(it - zero); }
2275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter() {}
2295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {}
2315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator==(spirv_inst_iter const &other) { return it == other.it; }
2335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator!=(spirv_inst_iter const &other) { return it != other.it; }
2355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
236cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++(int) {  // x++
2375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        spirv_inst_iter ii = *this;
2385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return ii;
2405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
242cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++() {  // ++x;
2435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return *this;
2455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The iterator and the value are the same thing.
2485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter &operator*() { return *this; }
2495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter const &operator*() const { return *this; }
2505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module {
25325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The spirv image itself
2545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    vector<uint32_t> words;
25525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // A mapping of <id> to the first word of its def. this is useful because walking type
25625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // trees, constant expressions, etc requires jumping all over the instruction stream.
2575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<unsigned, unsigned> def_index;
258c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    bool has_valid_spirv;
2595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module(VkShaderModuleCreateInfo const *pCreateInfo)
2615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
262c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski          def_index(),
263c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski          has_valid_spirv(true) {
2645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        build_def_index(this);
2655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
267c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    shader_module() : has_valid_spirv(false) {}
268c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski
26925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Expose begin() / end() to enable range-based for
270cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); }  // First insn
271cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); }          // Just past last insn
27225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Given an offset into the module, produce an iterator there.
2735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); }
2745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Gets an iterator to the definition of an id
2765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter get_def(unsigned id) const {
2775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto it = def_index.find(id);
2785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (it == def_index.end()) {
2795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return end();
2805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return at(it->second);
2825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO : This can be much smarter, using separate locks for separate global data
286b9e992386a44404152747d66817a733aa127e281Jeremy Hayesstatic std::mutex global_lock;
287593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
28879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis// Return IMAGE_VIEW_STATE ptr for specified imageView or else NULL
2899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_VIEW_STATE *GetImageViewState(const layer_data *dev_data, VkImageView image_view) {
2902c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto iv_it = dev_data->imageViewMap.find(image_view);
2912c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (iv_it == dev_data->imageViewMap.end()) {
2922c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis        return nullptr;
2932c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    }
2942c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    return iv_it->second.get();
2952c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis}
2969a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis// Return sampler node ptr for specified sampler or else NULL
2979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSAMPLER_STATE *GetSamplerState(const layer_data *dev_data, VkSampler sampler) {
2982c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto sampler_it = dev_data->samplerMap.find(sampler);
2992c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (sampler_it == dev_data->samplerMap.end()) {
3009a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis        return nullptr;
3019a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    }
3029a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    return sampler_it->second.get();
3039a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis}
3045cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return image state ptr for specified image or else NULL
3059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_STATE *GetImageState(const layer_data *dev_data, VkImage image) {
3066d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    auto img_it = dev_data->imageMap.find(image);
3076d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    if (img_it == dev_data->imageMap.end()) {
3086d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        return nullptr;
3096d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    }
3106d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    return img_it->second.get();
3116d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis}
3125cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return buffer state ptr for specified buffer or else NULL
3139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_STATE *GetBufferState(const layer_data *dev_data, VkBuffer buffer) {
3142c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto buff_it = dev_data->bufferMap.find(buffer);
3152c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (buff_it == dev_data->bufferMap.end()) {
3168718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        return nullptr;
3178718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    }
3188718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    return buff_it->second.get();
3198718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis}
320b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis// Return swapchain node for specified swapchain or else NULL
3219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSWAPCHAIN_NODE *GetSwapchainNode(const layer_data *dev_data, VkSwapchainKHR swapchain) {
322b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    auto swp_it = dev_data->device_extensions.swapchainMap.find(swapchain);
323b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swp_it == dev_data->device_extensions.swapchainMap.end()) {
324b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        return nullptr;
325b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    }
3263f687bf405355f3eec6bd1bc0e8d04daba37a0f9Tobin Ehlis    return swp_it->second.get();
327b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis}
328170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis// Return swapchain for specified image or else NULL
3299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisVkSwapchainKHR GetSwapchainFromImage(const layer_data *dev_data, VkImage image) {
330170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    auto img_it = dev_data->device_extensions.imageToSwapchainMap.find(image);
331170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    if (img_it == dev_data->device_extensions.imageToSwapchainMap.end()) {
332170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis        return VK_NULL_HANDLE;
333170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    }
334170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    return img_it->second;
335170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis}
3362f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis// Return buffer node ptr for specified buffer or else NULL
3379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_VIEW_STATE *GetBufferViewState(const layer_data *dev_data, VkBufferView buffer_view) {
33851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto bv_it = dev_data->bufferViewMap.find(buffer_view);
33951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (bv_it == dev_data->bufferViewMap.end()) {
3402f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis        return nullptr;
3412f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    }
3422f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    return bv_it->second.get();
3432f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis}
3448718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis
3459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFENCE_NODE *GetFenceNode(layer_data *dev_data, VkFence fence) {
34666fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->fenceMap.find(fence);
34766fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->fenceMap.end()) {
34866fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
34966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
35066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
35166fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
35266fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisEVENT_STATE *GetEventNode(layer_data *dev_data, VkEvent event) {
3549556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    auto it = dev_data->eventMap.find(event);
3559556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    if (it == dev_data->eventMap.end()) {
3569556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis        return nullptr;
3579556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    }
3589556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    return &it->second;
3599556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis}
3609556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis
3619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUERY_POOL_NODE *GetQueryPoolNode(layer_data *dev_data, VkQueryPool query_pool) {
362ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    auto it = dev_data->queryPoolMap.find(query_pool);
363ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    if (it == dev_data->queryPoolMap.end()) {
364ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis        return nullptr;
365ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    }
366ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    return &it->second;
367ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis}
368ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis
3699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUEUE_STATE *GetQueueState(layer_data *dev_data, VkQueue queue) {
37066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->queueMap.find(queue);
37166fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->queueMap.end()) {
37266fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
37366fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
37466fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
37566fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
37666fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSEMAPHORE_NODE *GetSemaphoreNode(layer_data *dev_data, VkSemaphore semaphore) {
3785e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    auto it = dev_data->semaphoreMap.find(semaphore);
3795e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    if (it == dev_data->semaphoreMap.end()) {
3805e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes        return nullptr;
3815e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    }
3825e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    return &it->second;
3835e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes}
3845e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes
3859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisCOMMAND_POOL_NODE *GetCommandPoolNode(layer_data *dev_data, VkCommandPool pool) {
3868d6a38de0389036581ada119e548180c614fe0efChris Forbes    auto it = dev_data->commandPoolMap.find(pool);
3878d6a38de0389036581ada119e548180c614fe0efChris Forbes    if (it == dev_data->commandPoolMap.end()) {
3888d6a38de0389036581ada119e548180c614fe0efChris Forbes        return nullptr;
3898d6a38de0389036581ada119e548180c614fe0efChris Forbes    }
3908d6a38de0389036581ada119e548180c614fe0efChris Forbes    return &it->second;
3918d6a38de0389036581ada119e548180c614fe0efChris Forbes}
3923bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
3939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisPHYSICAL_DEVICE_STATE *GetPhysicalDeviceState(instance_layer_data *instance_data, VkPhysicalDevice phys) {
394f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    auto it = instance_data->physical_device_map.find(phys);
395f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    if (it == instance_data->physical_device_map.end()) {
3963bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes        return nullptr;
3973bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    }
3983bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    return &it->second;
3993bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes}
4003bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
4019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSURFACE_STATE *GetSurfaceState(instance_layer_data *instance_data, VkSurfaceKHR surface) {
402747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    auto it = instance_data->surface_map.find(surface);
403747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (it == instance_data->surface_map.end()) {
404747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        return nullptr;
405747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
406747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return &it->second;
407747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
408747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
409f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Return ptr to memory binding for given handle of specified type
4107a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic BINDABLE *GetObjectMemBinding(layer_data *dev_data, uint64_t handle, VulkanObjectType type) {
4115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type) {
4127a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        case kVulkanObjectTypeImage:
4139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetImageState(dev_data, VkImage(handle));
4147a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        case kVulkanObjectTypeBuffer:
4159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetBufferState(dev_data, VkBuffer(handle));
416cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
417cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
4185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41994c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis    return nullptr;
4205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis// prototype
4229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *, const VkCommandBuffer);
42372d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis
4245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return ptr to info in map container containing mem, or NULL if not found
4255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Calls to this function should be wrapped in mutex
4269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDEVICE_MEM_INFO *GetMemObjInfo(const layer_data *dev_data, const VkDeviceMemory mem) {
42757fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    auto mem_it = dev_data->memObjMap.find(mem);
42857fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_it == dev_data->memObjMap.end()) {
4295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
4305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    return mem_it->second.get();
4325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void add_mem_obj_info(layer_data *dev_data, void *object, const VkDeviceMemory mem,
4355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             const VkMemoryAllocateInfo *pAllocateInfo) {
4365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(object != NULL);
4375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->memObjMap[mem] = unique_ptr<DEVICE_MEM_INFO>(new DEVICE_MEM_INFO(object, mem, pAllocateInfo));
4395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
440dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis
441cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given bound_object_handle, bound to given mem allocation, verify that the range for the bound object is valid
4427a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ValidateMemoryIsValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t bound_object_handle, VulkanObjectType type,
4437a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                  const char *functionName) {
4449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
445f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
446f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        if (!mem_info->bound_ranges[bound_object_handle].valid) {
447f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
448ea8e85ade623a09c601d939622cbd7740d8d66c9Tobin Ehlis                           reinterpret_cast<uint64_t &>(mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
449dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           "%s: Cannot read invalid region of memory allocation 0x%" PRIx64 " for bound %s object 0x%" PRIx64
450dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           ", please fill the memory before using.",
4517a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                           functionName, reinterpret_cast<uint64_t &>(mem), object_string[type], bound_object_handle);
452f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        }
453f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
454f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    return false;
455f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
4561facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis// For given image_state
4571facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then verify that image_state valid member is true
458f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else verify that the image's bound memory range is valid
45960568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageMemoryIsValid(layer_data *dev_data, IMAGE_STATE *image_state, const char *functionName) {
460e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
4611facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        if (!image_state->valid) {
462f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
463e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                           reinterpret_cast<uint64_t &>(image_state->binding.mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
464414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                           "%s: Cannot read invalid swapchain image 0x%" PRIx64 ", please fill the memory before using.",
4651facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                           functionName, reinterpret_cast<uint64_t &>(image_state->image));
4665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
468e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis        return ValidateMemoryIsValid(dev_data, image_state->binding.mem, reinterpret_cast<uint64_t &>(image_state->image),
4697a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                     kVulkanObjectTypeImage, functionName);
4705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
4725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4735cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// For given buffer_state, verify that the range it's bound to is valid
474c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskibool ValidateBufferMemoryIsValid(layer_data *dev_data, BUFFER_STATE *buffer_state, const char *functionName) {
4755cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    return ValidateMemoryIsValid(dev_data, buffer_state->binding.mem, reinterpret_cast<uint64_t &>(buffer_state->buffer),
4767a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                 kVulkanObjectTypeBuffer, functionName);
477f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
478f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For the given memory allocation, set the range bound by the given handle object to the valid param value
479f989de4217bce0f293121d0da53dc8328276370fTobin Ehlisstatic void SetMemoryValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, bool valid) {
4809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
481f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
482f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        mem_info->bound_ranges[handle].valid = valid;
483f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
484f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
485f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given image node
4861facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then set entire image_state to valid param value
487f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else set the image's bound memory range to valid param value
488623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinskivoid SetImageMemoryValid(layer_data *dev_data, IMAGE_STATE *image_state, bool valid) {
489e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
4901facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->valid = valid;
4915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
492e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis        SetMemoryValid(dev_data, image_state->binding.mem, reinterpret_cast<uint64_t &>(image_state->image), valid);
4935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
495f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given buffer node set the buffer's bound memory range to valid param value
496c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskivoid SetBufferMemoryValid(layer_data *dev_data, BUFFER_STATE *buffer_state, bool valid) {
4975cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    SetMemoryValid(dev_data, buffer_state->binding.mem, reinterpret_cast<uint64_t &>(buffer_state->buffer), valid);
498f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
499ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
50056f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given sampler and command buffer node
501d31a44af6da568692a73201825459689c9431867Tobin Ehlisvoid AddCommandBufferBindingSampler(GLOBAL_CB_NODE *cb_node, SAMPLER_STATE *sampler_state) {
502d31a44af6da568692a73201825459689c9431867Tobin Ehlis    sampler_state->cb_bindings.insert(cb_node);
503d31a44af6da568692a73201825459689c9431867Tobin Ehlis    cb_node->object_bindings.insert(
5047a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        {reinterpret_cast<uint64_t &>(sampler_state->sampler), kVulkanObjectTypeSampler });
50556f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis}
50656f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis
50756f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given image node and command buffer node
5081facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisvoid AddCommandBufferBindingImage(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state) {
509ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Skip validation if this image was created through WSI
510e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
511ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // First update CB binding in MemObj mini CB list
512d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        for (auto mem_binding : image_state->GetBoundMemory()) {
5139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
514d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            if (pMemInfo) {
515d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                pMemInfo->cb_bindings.insert(cb_node);
516d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                // Now update CBInfo's Mem reference list
517d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                cb_node->memObjs.insert(mem_binding);
518d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            }
519ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        }
520f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        // Now update cb binding for image
5217a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        cb_node->object_bindings.insert({reinterpret_cast<uint64_t &>(image_state->image), kVulkanObjectTypeImage });
5221facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->cb_bindings.insert(cb_node);
523ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
524ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
525ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
52603ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis// Create binding link between given image view node and its image with command buffer node
52703ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlisvoid AddCommandBufferBindingImageView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state) {
52803ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // First add bindings for imageView
52903ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
53003ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    cb_node->object_bindings.insert(
5317a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        {reinterpret_cast<uint64_t &>(view_state->image_view), kVulkanObjectTypeImageView });
5329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, view_state->create_info.image);
53303ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // Add bindings for image within imageView
5341facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
5351facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
53603ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    }
53703ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis}
53803ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis
539ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis// Create binding link between given buffer node and command buffer node
5405cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlisvoid AddCommandBufferBindingBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state) {
541ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // First update CB binding in MemObj mini CB list
5425cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    for (auto mem_binding : buffer_state->GetBoundMemory()) {
5439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
544d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        if (pMemInfo) {
545d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            pMemInfo->cb_bindings.insert(cb_node);
546d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            // Now update CBInfo's Mem reference list
547d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            cb_node->memObjs.insert(mem_binding);
548d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        }
549ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
550ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Now update cb binding for buffer
5517a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski    cb_node->object_bindings.insert({reinterpret_cast<uint64_t &>(buffer_state->buffer), kVulkanObjectTypeBuffer });
5525cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    buffer_state->cb_bindings.insert(cb_node);
553ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
554ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
55577b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis// Create binding link between given buffer view node and its buffer with command buffer node
55677b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlisvoid AddCommandBufferBindingBufferView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_VIEW_STATE *view_state) {
55777b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // First add bindings for bufferView
55877b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
55977b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    cb_node->object_bindings.insert(
5607a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        {reinterpret_cast<uint64_t &>(view_state->buffer_view), kVulkanObjectTypeBufferView });
5619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, view_state->create_info.buffer);
56277b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // Add bindings for buffer within bufferView
5635cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
5645cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, buffer_state);
56577b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    }
56677b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis}
56777b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis
568400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis// For every mem obj bound to particular CB, free bindings related to that CB
569d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlisstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
570d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis    if (cb_node) {
571d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        if (cb_node->memObjs.size() > 0) {
572d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            for (auto mem : cb_node->memObjs) {
5739a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                DEVICE_MEM_INFO *pInfo = GetMemObjInfo(dev_data, mem);
5745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pInfo) {
575d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                    pInfo->cb_bindings.erase(cb_node);
5765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
5775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
578d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            cb_node->memObjs.clear();
5795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
580d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        cb_node->validate_functions.clear();
5815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
584f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Clear a single object binding from given memory object, or report error if binding is missing
5857a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ClearMemoryObjectBinding(layer_data *dev_data, uint64_t handle, VulkanObjectType type, VkDeviceMemory mem) {
5869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
587f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // This obj is bound to a memory object. Remove the reference to this object in that memory object's list
588d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes    if (mem_info) {
589d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes        mem_info->obj_bindings.erase({handle, type});
590f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    }
591f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return false;
592f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis}
593f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis
594f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// ClearMemoryObjectBindings clears the binding of objects to memory
595f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  For the given object it pulls the memory bindings and makes sure that the bindings
596f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  no longer refer to the object being cleared. This occurs when objects are destroyed.
5977a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskibool ClearMemoryObjectBindings(layer_data *dev_data, uint64_t handle, VulkanObjectType type) {
598f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    bool skip = false;
599f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
600f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (mem_binding) {
601f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (!mem_binding->sparse) {
602f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            skip = ClearMemoryObjectBinding(dev_data, handle, type, mem_binding->binding.mem);
603cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Sparse, clear all bindings
604bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            for (auto &sparse_mem_binding : mem_binding->sparse_bindings) {
605f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                skip |= ClearMemoryObjectBinding(dev_data, handle, type, sparse_mem_binding.mem);
6065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
6075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
609f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return skip;
6105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
612888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// For given mem object, verify that it is not null or UNBOUND, if it is, report error. Return skip value.
613888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisbool VerifyBoundMemoryIsValid(const layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, const char *api_name,
61435ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                              const char *type_name, UNIQUE_VALIDATION_ERROR_CODE error_code) {
615888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    bool result = false;
616888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    if (VK_NULL_HANDLE == mem) {
617888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
618cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
619cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound. Memory should be bound by calling "
620cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "vkBind%sMemory(). %s",
62135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, type_name, validation_error_map[error_code]);
622888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    } else if (MEMORY_UNBOUND == mem) {
623888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
624cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
625cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound and previously bound memory was freed. "
626cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "Memory must not be freed prior to this operation. %s",
62735ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, validation_error_map[error_code]);
628888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    }
629888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    return result;
630888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis}
631888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis
632b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was ever bound to this image
63335ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToImage(const layer_data *dev_data, const IMAGE_STATE *image_state, const char *api_name,
63435ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                  UNIQUE_VALIDATION_ERROR_CODE error_code) {
635b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
6361facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (0 == (static_cast<uint32_t>(image_state->createInfo.flags) & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
63735ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        result = VerifyBoundMemoryIsValid(dev_data, image_state->binding.mem,
63835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                          reinterpret_cast<const uint64_t &>(image_state->image), api_name, "Image", error_code);
639b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
640b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
641b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
642b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
643b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was bound to this buffer
64435ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToBuffer(const layer_data *dev_data, const BUFFER_STATE *buffer_state, const char *api_name,
64535ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                   UNIQUE_VALIDATION_ERROR_CODE error_code) {
646b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
6475cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (0 == (static_cast<uint32_t>(buffer_state->createInfo.flags) & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) {
6485cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        result = VerifyBoundMemoryIsValid(dev_data, buffer_state->binding.mem,
64935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                          reinterpret_cast<const uint64_t &>(buffer_state->buffer), api_name, "Buffer", error_code);
650b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
651b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
652b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
653b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
6543a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// SetMemBinding is used to establish immutable, non-sparse binding between a single image/buffer object and memory object.
6553a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Corresponding valid usage checks are in ValidateSetMemBinding().
6567a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic void SetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VulkanObjectType type, const char *apiName) {
657c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    if (mem != VK_NULL_HANDLE) {
658c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
659c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        assert(mem_binding);
660c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
661c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        if (mem_info) {
662c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_info->obj_bindings.insert({handle, type});
663c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // For image objects, make sure default memory state is correctly set
664c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // TODO : What's the best/correct way to handle this?
6657a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            if (kVulkanObjectTypeImage == type) {
666c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                auto const image_state = GetImageState(dev_data, VkImage(handle));
667c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                if (image_state) {
668c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    VkImageCreateInfo ici = image_state->createInfo;
669c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
670c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                        // TODO::  More memory state transition stuff.
671c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    }
672c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                }
673c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            }
674c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_binding->binding.mem = mem;
675c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        }
676c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    }
677c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton}
6783a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton
6793a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Valid usage checks for a call to SetMemBinding().
6803a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// For NULL mem case, output warning
6813a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Make sure given object is in global object map
6823a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  IF a previous binding existed, output validation error
6833a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Otherwise, add reference from objectInfo to memoryInfo
6843a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Add reference off of objInfo
6853a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// TODO: We may need to refactor or pass in multiple valid usage statements to handle multiple valid usage conditions.
6867a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ValidateSetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VulkanObjectType type,
687c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                                  const char *apiName) {
6883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
689f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // It's an error to bind an object to NULL memory
690d3876b4ff7c293a14f73fe3622513d1fa91bf2d0Jeremy Hayes    if (mem != VK_NULL_HANDLE) {
691f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
692888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        assert(mem_binding);
69310ffe2d353eaff714ed92a2835af77d8b5042d31Cort        if (mem_binding->sparse) {
69410ffe2d353eaff714ed92a2835af77d8b5042d31Cort            UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_00804;
69510ffe2d353eaff714ed92a2835af77d8b5042d31Cort            const char *handle_type = "IMAGE";
69674300755ed9ec780d6073af71e47f201217008d6Cort Stratton            if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
69710ffe2d353eaff714ed92a2835af77d8b5042d31Cort                error_code = VALIDATION_ERROR_00792;
69810ffe2d353eaff714ed92a2835af77d8b5042d31Cort                handle_type = "BUFFER";
69910ffe2d353eaff714ed92a2835af77d8b5042d31Cort            } else {
70074300755ed9ec780d6073af71e47f201217008d6Cort Stratton                assert(strcmp(apiName, "vkBindImageMemory()") == 0);
70110ffe2d353eaff714ed92a2835af77d8b5042d31Cort            }
7023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
7033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(mem), __LINE__, error_code, "MEM",
7043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
7053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") which was created with sparse memory flags (VK_%s_CREATE_SPARSE_*_BIT). %s",
7063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            apiName, reinterpret_cast<uint64_t &>(mem), handle, handle_type, validation_error_map[error_code]);
70710ffe2d353eaff714ed92a2835af77d8b5042d31Cort        }
7089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
709888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        if (mem_info) {
7109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *prev_binding = GetMemObjInfo(dev_data, mem_binding->binding.mem);
711888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis            if (prev_binding) {
71298c2a17e1a549df84f4239f619bc0955f632cb43Cort                UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_00803;
71374300755ed9ec780d6073af71e47f201217008d6Cort Stratton                if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
71498c2a17e1a549df84f4239f619bc0955f632cb43Cort                    error_code = VALIDATION_ERROR_00791;
71598c2a17e1a549df84f4239f619bc0955f632cb43Cort                } else {
71674300755ed9ec780d6073af71e47f201217008d6Cort Stratton                    assert(strcmp(apiName, "vkBindImageMemory()") == 0);
71798c2a17e1a549df84f4239f619bc0955f632cb43Cort                }
7183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
7193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                reinterpret_cast<uint64_t &>(mem), __LINE__, error_code, "MEM",
7203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
7213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                ") which has already been bound to mem object 0x%" PRIxLEAST64 ". %s",
7223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                apiName, reinterpret_cast<uint64_t &>(mem), handle, reinterpret_cast<uint64_t &>(prev_binding->mem),
7233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                validation_error_map[error_code]);
724f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            } else if (mem_binding->binding.mem == MEMORY_UNBOUND) {
7253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
7263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                reinterpret_cast<uint64_t &>(mem), __LINE__, MEMTRACK_REBIND_OBJECT, "MEM",
7273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
7283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                ") which was previous bound to memory that has since been freed. Memory bindings are immutable in "
7293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "Vulkan so this attempt to bind to new memory is not allowed.",
7303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                apiName, reinterpret_cast<uint64_t &>(mem), handle);
7315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
7355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
7365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For NULL mem case, clear any previous binding Else...
7385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Make sure given object is in its object map
7395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  IF a previous binding existed, update binding
7405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference from objectInfo to memoryInfo
7415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference off of object's binding info
7420a1ce3dfd81c9f4efbe46f5ba5ddaea70bc4aa61Chris Forbes// Return VK_TRUE if addition is successful, VK_FALSE otherwise
743ece0e981ee4a5ad2572d146a89fc64d699d79f36Chris Forbesstatic bool SetSparseMemBinding(layer_data *dev_data, MEM_BINDING binding, uint64_t handle, VulkanObjectType type) {
7443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = VK_FALSE;
7455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Handle NULL case separately, just clear previous binding & decrement reference
746f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (binding.mem == VK_NULL_HANDLE) {
747f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        // TODO : This should cause the range of the resource to be unbound according to spec
7485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
749f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
750f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding);
751f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding->sparse);
7529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, binding.mem);
753f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (mem_info) {
754f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_info->obj_bindings.insert({handle, type});
7552e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis            // Need to set mem binding for this object
756f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_binding->sparse_bindings.insert(binding);
7575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
760caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis}
761caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis
7625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// SPIRV utility functions
7635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *module) {
7645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *module) {
7655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
766cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Types
767cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVoid:
768cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeBool:
769cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeInt:
770cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFloat:
771cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVector:
772cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeMatrix:
773cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage:
774cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampler:
775cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
776cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
777cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeRuntimeArray:
778cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeStruct:
779cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeOpaque:
780cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
781cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFunction:
782cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeEvent:
783cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeDeviceEvent:
784cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeReserveId:
785cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeQueue:
786cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePipe:
787cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(1)] = insn.offset();
788cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
7895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
790cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Fixed constants
791cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantTrue:
792cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantFalse:
793cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstant:
794cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantComposite:
795cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantSampler:
796cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantNull:
797cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
7995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
800cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Specialization constants
801cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantTrue:
802cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantFalse:
803cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstant:
804cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantComposite:
805cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantOp:
806cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
807cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
809cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Variables
810cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpVariable:
811cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
812cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
814cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Functions
815cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
816cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
817cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
819cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
820cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // We don't care about any other defs for now.
821cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) {
8275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
8285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpEntryPoint) {
8295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointName = (char const *)&insn.word(3);
8305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointStageBits = 1u << insn.word(1);
8315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) {
8335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return insn;
8345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return src->end();
8395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char const *storage_class_name(unsigned sc) {
8425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (sc) {
843cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassInput:
844cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "input";
845cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassOutput:
846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "output";
847cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniformConstant:
848cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "const uniform";
849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniform:
850cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "uniform";
851cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassWorkgroup:
852cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup local";
853cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassCrossWorkgroup:
854cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup global";
855cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPrivate:
856cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "private global";
857cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassFunction:
858cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "function";
859cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassGeneric:
860cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "generic";
861cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassAtomicCounter:
862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "atomic counter";
863cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassImage:
864cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image";
865cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPushConstant:
866cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "push constant";
867cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
868cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "unknown";
8695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
87225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Get the value of an integral constant
8735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisunsigned get_constant_value(shader_module const *src, unsigned id) {
8745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto value = src->get_def(id);
8755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(value != src->end());
8765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (value.opcode() != spv::OpConstant) {
87825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // TODO: Either ensure that the specialization transform is already performed on a module we're
87925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        //       considering here, OR -- specialize on the fly now.
8805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return 1;
8815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return value.word(3);
8845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8869ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) {
8875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
8885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
8895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
892cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "bool";
893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
894cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
897cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "float" << insn.word(2);
899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "vec" << insn.word(3) << " of ";
902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "mat" << insn.word(3) << " of ";
906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of ";
910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "ptr to " << storage_class_name(insn.word(2)) << " ";
914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(3));
915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "struct of (";
918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (unsigned i = 2; i < insn.len(); i++) {
919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                describe_type_inner(ss, src, insn.word(i));
920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (i == insn.len() - 1) {
921cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ")";
922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
923cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ", ";
924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
9259ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes            }
926cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler";
930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler+";
933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
937cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
938cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
939cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "oddtype";
940cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9449ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic std::string describe_type(shader_module const *src, unsigned type) {
9459ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    std::ostringstream ss;
9469ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    describe_type_inner(ss, src, type);
9479ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    return ss.str();
9489ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes}
9499ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes
950bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool is_narrow_numeric_type(spirv_inst_iter type) {
951cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat) return false;
95237576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    return type.word(2) < 64;
95337576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes}
95437576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
955bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool a_arrayed,
956bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        bool b_arrayed, bool relaxed) {
95725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk two type trees together, and complain about differences
9585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_insn = a->get_def(a_type);
9595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_insn = b->get_def(b_type);
9605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(a_insn != a->end());
9615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(b_insn != b->end());
9625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9637c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
96437576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
9657c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
9667c755c8aca6857046df9516d8336416165969cb9Chris Forbes
9675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
96825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We probably just found the extra level of arrayness in b_type: compare the type inside it to a_type
96937576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
97037576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    }
97137576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
97237576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    if (a_insn.opcode() == spv::OpTypeVector && relaxed && is_narrow_numeric_type(b_insn)) {
97337576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
9745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (a_insn.opcode() != b_insn.opcode()) {
9775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
9785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9807c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_insn.opcode() == spv::OpTypePointer) {
98125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Match on pointee type. storage class is expected to differ
98237576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
9837c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
9847c755c8aca6857046df9516d8336416165969cb9Chris Forbes
9857c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed || b_arrayed) {
98625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // If we havent resolved array-of-verts by here, we're not going to.
9877c755c8aca6857046df9516d8336416165969cb9Chris Forbes        return false;
9887c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
9897c755c8aca6857046df9516d8336416165969cb9Chris Forbes
9905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (a_insn.opcode()) {
991cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
992cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return true;
993cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
994cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width, signedness
995cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
996cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
997cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width
998cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2);
999cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1000cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1001cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (!types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false)) return false;
1002cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (relaxed && is_narrow_numeric_type(a->get_def(a_insn.word(2)))) {
1003cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) >= b_insn.word(3);
1004cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1005cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) == b_insn.word(3);
10065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1007cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1008cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1009cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1010cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   a_insn.word(3) == b_insn.word(3);
1011cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1012cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count. these all have the same layout. we don't get here if b_arrayed. This differs from
1013cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // vector & matrix types in that the array size is the id of a constant instruction, * not a literal within OpTypeArray
1014cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1015cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3));
1016cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct:
1017cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on all element types
1018cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            {
1019cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (a_insn.len() != b_insn.len()) {
1020cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return false;  // Structs cannot match if member counts differ
1021cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
10225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1023cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                for (unsigned i = 2; i < a_insn.len(); i++) {
1024cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (!types_match(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
1025cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return false;
1026cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
1027cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
1028cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1029cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return true;
1030cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1031cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1032cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Remaining types are CLisms, or may not appear in the interfaces we are interested in. Just claim no match.
1033cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
10345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10372c81be6aa02b10d9e225329977fa108ceda890a2Chris Forbesstatic unsigned value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, unsigned def) {
10385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it = map.find(id);
10395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (it == map.end())
10405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return def;
10415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    else
10425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return it->second;
10435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) {
10465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
10475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
10485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1050cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1051cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
1052cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // pointers around.
1053cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_locations_consumed_by_type(src, insn.word(3), strip_array_level);
1054cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1055cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (strip_array_level) {
1056cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_locations_consumed_by_type(src, insn.word(2), false);
1057cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1058cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false);
1059cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1060cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1061cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Num locations is the dimension * element size
1062cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false);
1063cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector: {
1064cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto scalar_type = src->get_def(insn.word(2));
1065cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto bit_width =
1066cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
1067cc52143fc093e1e62d2dacc4abc3966e04b6f6d6Chris Forbes
1068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Locations are 128-bit wide; 3- and 4-component vectors of 64 bit types require two.
1069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return (bit_width * insn.word(3) + 127) / 128;
1070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1072cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Everything else is just 1.
1073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
10745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1075cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO: extend to handle 64bit scalar types, whose vectors may need multiple locations.
10765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1079c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbesstatic unsigned get_locations_consumed_by_format(VkFormat format) {
1080c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    switch (format) {
1081cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SFLOAT:
1082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SINT:
1083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_UINT:
1084cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SFLOAT:
1085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SINT:
1086cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_UINT:
1087cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 2;
1088cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1089cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
1090c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    }
1091c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes}
1092c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes
10935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> location_t;
10945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> descriptor_slot_t;
10955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct interface_var {
10975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t id;
10985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t type_id;
10995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset;
1100b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    bool is_patch;
1101fff9393206f66a154438e16fa0562c989f425498Chris Forbes    bool is_block_member;
1102b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    bool is_relaxed_precision;
110325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: collect the name, too? Isn't required to be present.
11045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
11055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1106031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstruct shader_stage_attributes {
1107031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    char const *const name;
1108031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_input;
1109031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_output;
1110031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1111031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
1112031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstatic shader_stage_attributes shader_stage_attribs[] = {
1113bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"vertex shader", false, false},  {"tessellation control shader", true, true}, {"tessellation evaluation shader", true, false},
1114bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"geometry shader", true, false}, {"fragment shader", false, false},
1115031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1116031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
11175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) {
11185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (true) {
11195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def.opcode() == spv::OpTypePointer) {
11205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(3));
11215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
11225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(2));
11235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            is_array_of_verts = false;
11245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeStruct) {
11255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return def;
11265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
11275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return src->end();
11285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
11315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1132bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void collect_interface_block_members(shader_module const *src, std::map<location_t, interface_var> *out,
11335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                            std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts,
1134b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                                            uint32_t id, uint32_t type_id, bool is_patch) {
113525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk down the type_id presented, trying to determine whether it's actually an interface block.
1136031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts && !is_patch);
11375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) {
113825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // This isn't an interface block.
11395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return;
11405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> member_components;
11435b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes    std::unordered_map<unsigned, unsigned> member_relaxed_precision;
11445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
114525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk all the OpMemberDecorate for type's result id -- first pass, collect components.
11465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
11475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
11485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
11495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationComponent) {
11515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = insn.word(4);
11525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                member_components[member_index] = component;
11535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
11545b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes
11555b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            if (insn.word(3) == spv::DecorationRelaxedPrecision) {
11565b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                member_relaxed_precision[member_index] = 1;
11575b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            }
11585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
116125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Second pass -- produce the output, from Location decorations
11625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
11635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
11645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
11655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_type_id = type.word(2 + member_index);
11665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationLocation) {
11685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned location = insn.word(4);
11695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false);
11705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto component_it = member_components.find(member_index);
11715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = component_it == member_components.end() ? 0 : component_it->second;
11725b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                bool is_relaxed_precision = member_relaxed_precision.find(member_index) != member_relaxed_precision.end();
11735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1175b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
11765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
117725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                    // TODO: member index in interface_var too?
11785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = member_type_id;
11795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1180b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1181fff9393206f66a154438e16fa0562c989f425498Chris Forbes                    v.is_block_member = true;
11825b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
11833a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                    (*out)[std::make_pair(location + offset, component)] = v;
11845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
11855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
11865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
11895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1190bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic std::map<location_t, interface_var> collect_interface_by_location(shader_module const *src, spirv_inst_iter entrypoint,
1191bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                         spv::StorageClass sinterface, bool is_array_of_verts) {
11925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_locations;
11935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_builtins;
11945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_components;
11955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> blocks;
1196b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    std::unordered_map<unsigned, unsigned> var_patch;
1197b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    std::unordered_map<unsigned, unsigned> var_relaxed_precision;
11985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
120025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We consider two interface models: SSO rendezvous-by-location, and builtins. Complain about anything that
120125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // fits neither model.
12025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
12035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationLocation) {
12045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_locations[insn.word(1)] = insn.word(3);
12055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBuiltIn) {
12085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_builtins[insn.word(1)] = insn.word(3);
12095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationComponent) {
12125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_components[insn.word(1)] = insn.word(3);
12135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBlock) {
12165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                blocks[insn.word(1)] = 1;
12175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1218b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes
1219b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            if (insn.word(2) == spv::DecorationPatch) {
1220b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                var_patch[insn.word(1)] = 1;
1221b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            }
1222b0436668e6594b8528e96de7bed208399fb2431dChris Forbes
1223b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            if (insn.word(2) == spv::DecorationRelaxedPrecision) {
1224b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                var_relaxed_precision[insn.word(1)] = 1;
1225b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            }
12265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
122925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle grouped decorations
123025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle index=1 dual source outputs from FS -- two vars will have the same location, and we DON'T want to clobber.
12315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
123225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the end of the entrypoint's name string. additional zero bytes follow the actual null terminator, to fill out the
123325002b75574f762c62b1a00a595bab04ebb25452Mark 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.
1234c15b801a6e1a5dd5eed09e689aecdde7c4a90a5bMichael Mc Donnell    uint32_t word = 3;
12355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (entrypoint.word(word) & 0xff000000u) {
12365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ++word;
12375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ++word;
12395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12403a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::map<location_t, interface_var> out;
12413a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
12425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; word < entrypoint.len(); word++) {
12435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(entrypoint.word(word));
12445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
12455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn.opcode() == spv::OpVariable);
12465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12471d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill        if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
12485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned id = insn.word(2);
12495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned type = insn.word(1);
12505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int location = value_or_default(var_locations, id, -1);
12525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int builtin = value_or_default(var_builtins, id, -1);
1253cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            unsigned component = value_or_default(var_components, id, 0);  // Unspecified is OK, is 0
1254b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            bool is_patch = var_patch.find(id) != var_patch.end();
1255b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            bool is_relaxed_precision = var_relaxed_precision.find(id) != var_relaxed_precision.end();
12565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
125725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // All variables and interface block members in the Input or Output storage classes must be decorated with either
125825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // a builtin or an explicit location.
125925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            //
126025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // TODO: integrate the interface block support here. For now, don't complain -- a valid SPIRV module will only hit
126125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // this path for the interface block case, as the individual members of the type are decorated, rather than
126225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // variable declarations.
12635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (location != -1) {
126525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // A user-defined interface variable, with a location. Where a variable occupied multiple locations, emit
126625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // one result for each.
12677c755c8aca6857046df9516d8336416165969cb9Chris Forbes                unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts && !is_patch);
12685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1269b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
12705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
12715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = type;
12725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1273b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1274b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
12755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    out[std::make_pair(location + offset, component)] = v;
12765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
12775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (builtin == -1) {
127825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // An interface block instance
12793a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                collect_interface_block_members(src, &out, blocks, is_array_of_verts, id, type, is_patch);
12805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12833a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
12843a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
12855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
128712b7fc342b53fbdd399aae4a85959e37685936acChris Forbesstatic vector<std::pair<uint32_t, interface_var>> collect_interface_by_input_attachment_index(
128812b7fc342b53fbdd399aae4a85959e37685936acChris Forbes    shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
12893a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<uint32_t, interface_var>> out;
1290745d49409296f060402b57950384caadb636a2b2Chris Forbes
1291745d49409296f060402b57950384caadb636a2b2Chris Forbes    for (auto insn : *src) {
1292745d49409296f060402b57950384caadb636a2b2Chris Forbes        if (insn.opcode() == spv::OpDecorate) {
1293745d49409296f060402b57950384caadb636a2b2Chris Forbes            if (insn.word(2) == spv::DecorationInputAttachmentIndex) {
1294745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto attachment_index = insn.word(3);
1295745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto id = insn.word(1);
1296745d49409296f060402b57950384caadb636a2b2Chris Forbes
1297745d49409296f060402b57950384caadb636a2b2Chris Forbes                if (accessible_ids.count(id)) {
1298745d49409296f060402b57950384caadb636a2b2Chris Forbes                    auto def = src->get_def(id);
1299745d49409296f060402b57950384caadb636a2b2Chris Forbes                    assert(def != src->end());
1300745d49409296f060402b57950384caadb636a2b2Chris Forbes
1301745d49409296f060402b57950384caadb636a2b2Chris Forbes                    if (def.opcode() == spv::OpVariable && insn.word(3) == spv::StorageClassUniformConstant) {
1302e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        auto num_locations = get_locations_consumed_by_type(src, def.word(1), false);
1303e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        for (unsigned int offset = 0; offset < num_locations; offset++) {
1304b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                            interface_var v = {};
1305e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.id = id;
1306e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.type_id = def.word(1);
1307e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.offset = offset;
1308e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            out.emplace_back(attachment_index + offset, v);
1309e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        }
1310745d49409296f060402b57950384caadb636a2b2Chris Forbes                    }
1311745d49409296f060402b57950384caadb636a2b2Chris Forbes                }
1312745d49409296f060402b57950384caadb636a2b2Chris Forbes            }
1313745d49409296f060402b57950384caadb636a2b2Chris Forbes        }
1314745d49409296f060402b57950384caadb636a2b2Chris Forbes    }
13153a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
13163a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
1317745d49409296f060402b57950384caadb636a2b2Chris Forbes}
1318745d49409296f060402b57950384caadb636a2b2Chris Forbes
1319cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic std::vector<std::pair<descriptor_slot_t, interface_var>> collect_interface_by_descriptor_slot(
1320cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
13215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_sets;
13225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_bindings;
13235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
132525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // All variables in the Uniform or UniformConstant storage classes are required to be decorated with both
132625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // DecorationDescriptorSet and DecorationBinding.
13275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
13285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationDescriptorSet) {
13295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_sets[insn.word(1)] = insn.word(3);
13305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBinding) {
13335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_bindings[insn.word(1)] = insn.word(3);
13345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13383a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<descriptor_slot_t, interface_var>> out;
13393a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
13405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
13415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
13425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
13435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpVariable &&
13455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) {
13465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned set = value_or_default(var_sets, insn.word(2), 0);
13475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned binding = value_or_default(var_bindings, insn.word(2), 0);
13485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1349b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            interface_var v = {};
13505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.id = insn.word(2);
13515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.type_id = insn.word(1);
1352cefd4dd8e03c5dae11a05d04a03cb856190358e0Chris Forbes            out.emplace_back(std::make_pair(set, binding), v);
13535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13553a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
13563a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
13575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
13585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1359edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_interface_between_stages(debug_report_data *report_data, shader_module const *producer,
1360031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              spirv_inst_iter producer_entrypoint, shader_stage_attributes const *producer_stage,
13615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                              shader_module const *consumer, spirv_inst_iter consumer_entrypoint,
1362031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              shader_stage_attributes const *consumer_stage) {
13631b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
13645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1365bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto outputs =
1366bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(producer, producer_entrypoint, spv::StorageClassOutput, producer_stage->arrayed_output);
1367bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto inputs =
1368bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(consumer, consumer_entrypoint, spv::StorageClassInput, consumer_stage->arrayed_input);
13695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_it = outputs.begin();
13715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_it = inputs.begin();
13725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
137325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Maps sorted by key (location); walk them together to find mismatches
13745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
13755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
13765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
13775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
13785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
13795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
13811b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
13821b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
13831b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "%s writes to output location %u.%u which is not consumed by %s", producer_stage->name, a_first.first,
13841b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            a_first.second, consumer_stage->name);
13855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
13865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (a_at_end || a_first > b_first) {
13871b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
13881b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "%s consumes input location %u.%u which is not written by %s",
13891b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            consumer_stage->name, b_first.first, b_first.second, producer_stage->name);
13905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
13915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1392fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // subtleties of arrayed interfaces:
1393fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_patch, then the member is not arrayed, even though the interface may be.
1394fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_block_member, then the extra array level of an arrayed interface is not
1395fff9393206f66a154438e16fa0562c989f425498Chris Forbes            //   expressed in the member type -- it's expressed in the block type.
13960f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (!types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id,
1397fff9393206f66a154438e16fa0562c989f425498Chris Forbes                             producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
1398bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member, true)) {
13991b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
14001b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'",
14011b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                a_first.first, a_first.second, describe_type(producer, a_it->second.type_id).c_str(),
14021b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                describe_type(consumer, b_it->second.type_id).c_str());
14035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
14040f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (a_it->second.is_patch != b_it->second.is_patch) {
14051b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
14061b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
14071b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Decoration mismatch on location %u.%u: is per-%s in %s stage but "
14081b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "per-%s in %s stage",
14091b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                a_first.first, a_first.second, a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
14101b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name);
14110f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            }
141217c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            if (a_it->second.is_relaxed_precision != b_it->second.is_relaxed_precision) {
14131b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
14141b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
14151b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Decoration mismatch on location %u.%u: %s and %s stages differ in precision", a_first.first,
14161b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                a_first.second, producer_stage->name, consumer_stage->name);
141717c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            }
14185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
14195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
14205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14231b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
14245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisenum FORMAT_TYPE {
1427f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_FLOAT = 1,  // UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader
1428f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_SINT = 2,
1429f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_UINT = 4,
14305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
14315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_format_type(VkFormat fmt) {
143328f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (FormatIsSInt(fmt))
143428f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return FORMAT_TYPE_SINT;
143528f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (FormatIsUInt(fmt))
143628f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return FORMAT_TYPE_UINT;
143728f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (FormatIsDepthAndStencil(fmt))
143828f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return FORMAT_TYPE_FLOAT | FORMAT_TYPE_UINT;
143928f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (fmt == VK_FORMAT_UNDEFINED)
144028f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return 0;
144128f7140700a1624f4836243204237c80645e0fb9Chris Forbes    // everything else -- UNORM/SNORM/FLOAT/USCALED/SSCALED is all float in the shader.
144228f7140700a1624f4836243204237c80645e0fb9Chris Forbes    return FORMAT_TYPE_FLOAT;
14435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
144525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// characterizes a SPIR-V type appearing in an interface to a FF stage, for comparison to a VkFormat's characterization above.
14465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_fundamental_type(shader_module const *src, unsigned type) {
14475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
14485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
14495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
1453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_FLOAT;
1455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1460cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1462cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(3));
1463cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
1464cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1465cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1466cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1467f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            return 0;
14685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) {
14728e88ad80aacad2085e76016e7bb29d243ce7f7b6Chris Forbes    uint32_t bit_pos = uint32_t(u_ffs(stage));
14735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return bit_pos - 1;
14745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1476edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_consistency(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi) {
147725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk the binding descriptions, which describe the step rate and stride of each vertex buffer.  Each binding should
147825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // be specified only once.
14795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
14801b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
14815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
14835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto desc = &vi->pVertexBindingDescriptions[i];
14845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto &binding = bindings[desc->binding];
14855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (binding) {
14864f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes            // TODO: VALIDATION_ERROR_02105 perhaps?
14871b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1488bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INCONSISTENT_VI, "SC", "Duplicate vertex input binding descriptions for binding %d",
14891b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                        desc->binding);
14905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
14915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            binding = desc;
14925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14951b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
14965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1498edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_against_vs_inputs(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi,
14995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                          shader_module const *vs, spirv_inst_iter entrypoint) {
15001b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
15015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15023a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto inputs = collect_interface_by_location(vs, entrypoint, spv::StorageClassInput, false);
15035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
150425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Build index by location
15055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
15065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
1507c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) {
1508c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            auto num_locations = get_locations_consumed_by_format(vi->pVertexAttributeDescriptions[i].format);
1509c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            for (auto j = 0u; j < num_locations; j++) {
1510c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes                attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
1511c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            }
1512c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        }
15135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_a = attribs.begin();
15165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_b = inputs.begin();
15171730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes    bool used = false;
15185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
15205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
15215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
15225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? 0 : it_a->first;
15235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? 0 : it_b->first.first;
15245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!a_at_end && (b_at_end || a_first < b_first)) {
15255b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski            if (!used && log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
15265b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski                                 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1527bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "Vertex attribute at location %d not consumed by vertex shader", a_first)) {
15281b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip = true;
15295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15301730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = false;
15315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_a++;
15325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (!b_at_end && (a_at_end || b_first < a_first)) {
15331b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
15341b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Vertex shader consumes input at location %d but not provided",
15351b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            b_first);
15365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
15375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
15385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned attrib_type = get_format_type(it_a->second->format);
15395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
15405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
154125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
1542f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            if (!(attrib_type & input_type)) {
15431b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
15441b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
15451b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Attribute type of `%s` at location %d does not match vertex shader input type of `%s`",
15461b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                string_VkFormat(it_a->second->format), a_first, describe_type(vs, it_b->second.type_id).c_str());
15475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
154925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
15501730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = true;
15515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
15525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15551b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
15565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1558edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_fs_outputs_against_render_pass(debug_report_data *report_data, shader_module const *fs,
15598da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    spirv_inst_iter entrypoint, VkRenderPassCreateInfo const *rpci,
15608da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    uint32_t subpass_index) {
1561025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    std::map<uint32_t, VkFormat> color_attachments;
15628da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    auto subpass = rpci->pSubpasses[subpass_index];
15638da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    for (auto i = 0u; i < subpass.colorAttachmentCount; ++i) {
1564d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        uint32_t attachment = subpass.pColorAttachments[i].attachment;
1565cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == VK_ATTACHMENT_UNUSED) continue;
1566d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        if (rpci->pAttachments[attachment].format != VK_FORMAT_UNDEFINED) {
1567d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis            color_attachments[i] = rpci->pAttachments[attachment].format;
1568025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        }
1569025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    }
1570025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
15711b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
15725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
157325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: dual source blend index (spv::DecIndex, zero if not provided)
15745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15753a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto outputs = collect_interface_by_location(fs, entrypoint, spv::StorageClassOutput, false);
15765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1577025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_a = outputs.begin();
1578025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_b = color_attachments.begin();
15795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
158025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk attachment list and outputs together
1581025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
1582025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    while ((outputs.size() > 0 && it_a != outputs.end()) || (color_attachments.size() > 0 && it_b != color_attachments.end())) {
1583025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool a_at_end = outputs.size() == 0 || it_a == outputs.end();
1584025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool b_at_end = color_attachments.size() == 0 || it_b == color_attachments.end();
15855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1586025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        if (!a_at_end && (b_at_end || it_a->first.first < it_b->first)) {
15871b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
15881b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
15891b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "fragment shader writes to output location %d with no matching attachment", it_a->first.first);
1590025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1591025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        } else if (!b_at_end && (a_at_end || it_a->first.first > it_b->first)) {
15921b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
15931b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by fragment shader", it_b->first);
1594025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
15955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1596025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned output_type = get_fundamental_type(fs, it_a->second.type_id);
1597025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned att_type = get_format_type(it_b->second);
15985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
159925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
1600f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            if (!(output_type & att_type)) {
16011b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
16021b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
16031b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Attachment %d of type `%s` does not match fragment shader output type of `%s`", it_b->first,
16041b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                string_VkFormat(it_b->second), describe_type(fs, it_a->second.type_id).c_str());
16055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
16065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
160725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
1608025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1609025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
16105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16131b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
16145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
161625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// For some analyses, we need to know about all ids referenced by the static call tree of a particular entrypoint. This is
161725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// important for identifying the set of shader resources actually used by an entrypoint, for example.
161825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
161925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//  - NOT the shader input/output interfaces.
162025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//
162125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
162225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// converting parts of this to be generated from the machine-readable spec instead.
16233a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbesstatic std::unordered_set<uint32_t> mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint) {
16243a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::unordered_set<uint32_t> ids;
16255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_set<uint32_t> worklist;
16265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    worklist.insert(entrypoint.word(2));
16275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!worklist.empty()) {
16295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id_iter = worklist.begin();
16305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id = *id_iter;
16315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        worklist.erase(id_iter);
16325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
16345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn == src->end()) {
163525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // ID is something we didn't collect in build_def_index. that's OK -- we'll stumble across all kinds of things here
163625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // that we may not care about.
16375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            continue;
16385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
164025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Try to add to the output set
16415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!ids.insert(id).second) {
1642cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            continue;  // If we already saw this id, we don't want to walk it again.
16435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
1646cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
1647cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Scan whole body of the function, enlisting anything interesting
1648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1649cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    switch (insn.opcode()) {
1650cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpLoad:
1651cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicLoad:
1652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicExchange:
1653cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchange:
1654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchangeWeak:
1655cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIIncrement:
1656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIDecrement:
1657cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIAdd:
1658cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicISub:
1659cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMin:
1660cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMin:
1661cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMax:
1662cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMax:
1663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicAnd:
1664cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicOr:
1665cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicXor:
1666cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // ptr
1667cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1668cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpStore:
1669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicStore:
1670cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // ptr
1671cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1672cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAccessChain:
1673cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpInBoundsAccessChain:
1674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // base ptr
1675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1676cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpSampledImage:
1677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleImplicitLod:
1678cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleExplicitLod:
1679cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefImplicitLod:
1680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefExplicitLod:
1681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjImplicitLod:
1682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjExplicitLod:
1683cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefImplicitLod:
1684cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefExplicitLod:
1685cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageFetch:
1686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageGather:
1687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageDrefGather:
1688cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageRead:
1689cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImage:
1690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryFormat:
1691cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryOrder:
1692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySizeLod:
1693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySize:
1694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLod:
1695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLevels:
1696cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySamples:
1697cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleImplicitLod:
1698cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleExplicitLod:
1699cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefImplicitLod:
1700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefExplicitLod:
1701cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjImplicitLod:
1702cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjExplicitLod:
1703cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefImplicitLod:
1704cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefExplicitLod:
1705cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseFetch:
1706cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseGather:
1707cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseDrefGather:
1708cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageTexelPointer:
1709cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // Image or sampled image
1710cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1711cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageWrite:
1712cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // Image -- different operand order to above
1713cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1714cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpFunctionCall:
1715cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 3; i < insn.len(); i++) {
1716cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // fn itself, and all args
1717cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1718cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
17195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1720cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpExtInst:
1721cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 5; i < insn.len(); i++) {
1722cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // Operands to ext inst
1723cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1724cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
17255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
17265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
1727cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
17285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17303a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
17313a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return ids;
17325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1734edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_block_against_pipeline(debug_report_data *report_data,
1735416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                          std::vector<VkPushConstantRange> const *push_constant_ranges,
17365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          shader_module const *src, spirv_inst_iter type,
17375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          VkShaderStageFlagBits stage) {
17381b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
17395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
174025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off ptrs etc
17415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    type = get_struct_type(src, type, false);
17425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(type != src->end());
17435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
174425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate directly off the offsets. this isn't quite correct for arrays and matrices, but is a good first step.
174525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: arrays, matrices, weird sizes
17465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
17475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
17485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationOffset) {
17495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned offset = insn.word(4);
1750cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto size = 4;  // Bytes; TODO: calculate this based on the type
17515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                bool found_range = false;
1753416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                for (auto const &range : *push_constant_ranges) {
17545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (range.offset <= offset && range.offset + range.size >= offset + size) {
17555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        found_range = true;
17565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if ((range.stageFlags & stage) == 0) {
17581b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
17591b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            __LINE__, SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC",
17601b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            "Push constant range covering variable starting at "
17611b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            "offset %u not accessible from stage %s",
17621b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            offset, string_VkShaderStageFlagBits(stage));
17635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
17645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        break;
17665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
17675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
17685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!found_range) {
17701b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
17711b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    __LINE__, SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
17721b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    "Push constant range covering variable starting at "
17731b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    "offset %u not declared in layout",
17741b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    offset);
17755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
17765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17801b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
17815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1783edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_usage(debug_report_data *report_data,
1784416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                         std::vector<VkPushConstantRange> const *push_constant_ranges, shader_module const *src,
17855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                         std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
17861b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
17875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
17895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto def_insn = src->get_def(id);
17905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
17911b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= validate_push_constant_block_against_pipeline(report_data, push_constant_ranges, src,
1792416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                                  src->get_def(def_insn.word(1)), stage);
17935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17961b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
17975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1799fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis// For given pipelineLayout verify that the set_layout_node at slot.first
1800fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis//  has the requested binding at slot.second and return ptr to that binding
1801bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkDescriptorSetLayoutBinding const *get_descriptor_binding(PIPELINE_LAYOUT_NODE const *pipelineLayout,
1802bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  descriptor_slot_t slot) {
1803cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pipelineLayout) return nullptr;
18045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1805cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (slot.first >= pipelineLayout->set_layouts.size()) return nullptr;
18065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1807416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    return pipelineLayout->set_layouts[slot.first]->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
18085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Check object status for selected flag state
181151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool validate_status(layer_data *dev_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
18124f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            const char *fail_msg, UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
18133d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (!(pNode->status & status_mask)) {
18144f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        char const *const message = validation_error_map[msg_code];
181551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
18164f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                       reinterpret_cast<const uint64_t &>(pNode->commandBuffer), __LINE__, msg_code, "DS",
18174f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                       "command buffer object 0x%p: %s. %s.", pNode->commandBuffer, fail_msg, message);
18185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1819e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
18205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Retrieve pipeline node ptr for given pipeline object
182351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_STATE *getPipelineState(layer_data const *dev_data, VkPipeline pipeline) {
182451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineMap.find(pipeline);
182551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineMap.end()) {
1826ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        return nullptr;
18275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1828ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    return it->second;
18295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisRENDER_PASS_STATE *GetRenderPassState(layer_data const *dev_data, VkRenderPass renderpass) {
183251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->renderPassMap.find(renderpass);
183351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->renderPassMap.end()) {
183416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes        return nullptr;
183516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes    }
1836fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    return it->second.get();
183716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes}
183816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes
18399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFRAMEBUFFER_STATE *GetFramebufferState(const layer_data *dev_data, VkFramebuffer framebuffer) {
184051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->frameBufferMap.find(framebuffer);
184151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->frameBufferMap.end()) {
1842f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes        return nullptr;
1843f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes    }
184404861caca7eb93a5241b164e8480bb93c826902cTobin Ehlis    return it->second.get();
1845f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes}
1846f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes
18479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSetLayout const *GetDescriptorSetLayout(layer_data const *dev_data, VkDescriptorSetLayout dsLayout) {
184851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->descriptorSetLayoutMap.find(dsLayout);
184951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->descriptorSetLayoutMap.end()) {
185011f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes        return nullptr;
185111f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    }
185211f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    return it->second;
185311f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes}
185411f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes
185551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_LAYOUT_NODE const *getPipelineLayout(layer_data const *dev_data, VkPipelineLayout pipeLayout) {
185651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineLayoutMap.find(pipeLayout);
185751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineLayoutMap.end()) {
18584a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes        return nullptr;
18594a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    }
18604a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    return &it->second;
18614a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes}
18624a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes
1863e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if for a given PSO, the given state enum is dynamic, else return false
18644c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool isDynamic(const PIPELINE_STATE *pPipeline, const VkDynamicState state) {
18655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) {
18665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
1867cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) return true;
18685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1870e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
18715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate state stored as flags at time of draw call
18744f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayesstatic bool validate_draw_state_flags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe, bool indexed,
18754f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                      UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
18769c4006684a13db43f0dbc8d0015a9ef34872ca09Chris Forbes    bool result = false;
1877ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipe->graphicsPipelineCI.pInputAssemblyState &&
1878ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        ((pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
1879ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         (pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP))) {
18803d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_LINE_WIDTH_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18814f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic line width state not set for this command buffer", msg_code);
18823d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
188345824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pRasterizationState &&
188445824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pRasterizationState->depthBiasEnable == VK_TRUE)) {
18853d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BIAS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18864f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bias state not set for this command buffer", msg_code);
18873d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
18883d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->blendConstantsEnabled) {
18893d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_BLEND_CONSTANTS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18904f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic blend constants state not set for this command buffer", msg_code);
18913d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
189245824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
189345824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE)) {
18943d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BOUNDS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18954f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bounds state not set for this command buffer", msg_code);
18963d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
189745824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
189845824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->stencilTestEnable == VK_TRUE)) {
18993d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
19004f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil read mask state not set for this command buffer", msg_code);
19013d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
19024f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil write mask state not set for this command buffer", msg_code);
19033d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
19044f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil reference state not set for this command buffer", msg_code);
19053d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
19061c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (indexed) {
19073d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_INDEX_BUFFER_BOUND, VK_DEBUG_REPORT_ERROR_BIT_EXT,
19084f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Index buffer object not bound to this command buffer when Indexed Draw attempted", msg_code);
19093d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
19104f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes
19115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
19125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
19135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify attachment reference compatibility according to spec
19155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this
19165ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski//  If both AttachmentReference arrays have requested index, check their corresponding AttachmentDescriptions
19175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//   to make sure that format and samples counts match.
19185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If not, they are not compatible.
19195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary,
19205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments,
19215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentReference *pSecondary, const uint32_t secondaryCount,
19225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentDescription *pSecondaryAttachments) {
1923e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    // Check potential NULL cases first to avoid nullptr issues later
1924e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    if (pPrimary == nullptr) {
1925e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        if (pSecondary == nullptr) {
1926e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis            return true;
1927e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        }
1928e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
1929e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    } else if (pSecondary == nullptr) {
1930e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
1931e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    }
1932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (index >= primaryCount) {  // Check secondary as if primary is VK_ATTACHMENT_UNUSED
1933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pSecondary[index].attachment) return true;
1934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (index >= secondaryCount) {  // Check primary as if secondary is VK_ATTACHMENT_UNUSED
1935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pPrimary[index].attachment) return true;
1936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // Format and sample count must match
19375ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) && (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
19385ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return true;
19395ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        } else if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) || (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
19405ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return false;
19415ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        }
19425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((pPrimaryAttachments[pPrimary[index].attachment].format ==
19435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].format) &&
19445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (pPrimaryAttachments[pPrimary[index].attachment].samples ==
19455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].samples))
19465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return true;
19475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
19485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Format and sample counts didn't match
19495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
19505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1951a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// TODO : Scrub verify_renderpass_compatibility() and validateRenderPassCompatibility() and unify them and/or share code
1952266231a5421564c314f6b5d5bd3fed26fd389484Chris Forbes// For given primary RenderPass object and secondary RenderPassCreateInfo, verify that they're compatible
195351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verify_renderpass_compatibility(const layer_data *dev_data, const VkRenderPassCreateInfo *primaryRPCI,
19548da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                            const VkRenderPassCreateInfo *secondaryRPCI, string &errorMsg) {
19555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
1956c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
19575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
19585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses.";
19595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
19605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
19615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
19625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t spIndex = 0;
19635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) {
19645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible
19655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
19665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
19675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount);
19685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) {
19695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount,
19705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments,
19715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
1972c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
19735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
19745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
19755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
19765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments,
19775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         primaryColorCount, primaryRPCI->pAttachments,
19785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryRPCI->pSubpasses[spIndex].pResolveAttachments,
19795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryColorCount, secondaryRPCI->pAttachments)) {
1980c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
19815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
19825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
19835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
19845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
19855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
1986fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
1987bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (!attachment_references_compatible(0, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 1,
1988bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
1989fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes                                              1, secondaryRPCI->pAttachments)) {
1990c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes            stringstream errorStr;
1991fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorStr << "depth/stencil attachments of subpass index " << spIndex << " are not compatible.";
1992fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorMsg = errorStr.str();
1993fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            return false;
1994fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes        }
1995fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
19965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
19975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
19985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount);
19995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < inputMax; ++i) {
20005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryColorCount,
20015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments,
20025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
2003c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
20045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible.";
20055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
20065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
20075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return true;
20115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2013397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
2014397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// pipelineLayout[layoutIndex]
201512b7fc342b53fbdd399aae4a85959e37685936acChris Forbesstatic bool verify_set_layout_compatibility(const cvdescriptorset::DescriptorSet *descriptor_set,
201669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            PIPELINE_LAYOUT_NODE const *pipeline_layout, const uint32_t layoutIndex,
201769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            string &errorMsg) {
2018416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto num_sets = pipeline_layout->set_layouts.size();
20199b5d124aff50234cb0450e1b805baef577c90d83Tobin Ehlis    if (layoutIndex >= num_sets) {
2020c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
202169b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        errorStr << "VkPipelineLayout (" << pipeline_layout->layout << ") only contains " << num_sets
202269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << " setLayouts corresponding to sets 0-" << num_sets - 1 << ", but you're attempting to bind set to index "
202369b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << layoutIndex;
20245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
20255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
20265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2027416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto layout_node = pipeline_layout->set_layouts[layoutIndex];
20281c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    return descriptor_set->IsCompatible(layout_node, &errorMsg);
20295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that data for each specialization entry is fully contained within the buffer.
2032edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_specialization_offsets(debug_report_data *report_data, VkPipelineShaderStageCreateInfo const *info) {
20331b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
20345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkSpecializationInfo const *spec = info->pSpecializationInfo;
20365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (spec) {
20385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto i = 0u; i < spec->mapEntryCount; i++) {
20394f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes            // TODO: This is a good place for VALIDATION_ERROR_00589.
20405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
20411b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
20421b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                VALIDATION_ERROR_00590, "SC",
20431b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Specialization entry %u (for constant id %u) references memory outside provided "
20441b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER
20451b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                " bytes provided). %s.",
20461b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
20471b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize,
20481b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                validation_error_map[VALIDATION_ERROR_00590]);
20495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20531b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
20545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2056bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool descriptor_type_match(shader_module const *module, uint32_t type_id, VkDescriptorType descriptor_type,
2057bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  unsigned &descriptor_count) {
20585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto type = module->get_def(type_id);
20595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20601b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes    descriptor_count = 1;
20611b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes
206225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off any array or ptrs. Where we remove array levels, adjust the  descriptor count for each dimension.
20635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) {
20647b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        if (type.opcode() == spv::OpTypeArray) {
20657b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            descriptor_count *= get_constant_value(module, type.word(3));
20667b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(2));
2067bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
20687b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(3));
20697b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        }
20705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type.opcode()) {
2073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
2074cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (auto insn : *module) {
2075cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
2076cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (insn.word(2) == spv::DecorationBlock) {
2077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
2078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
2079cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    } else if (insn.word(2) == spv::DecorationBufferBlock) {
2080cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
2081cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
2082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
20835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
20845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2086cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Invalid
2087cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
2088cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
20895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2090cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
2091cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER || descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
20925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2093cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
2094cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) {
2095cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
2096cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // buffer descriptor doesn't really provide one. Allow this slight mismatch.
2097cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto image_type = module->get_def(type.word(2));
2098cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = image_type.word(3);
2099cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto sampled = image_type.word(7);
2100cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return dim == spv::DimBuffer && sampled == 1;
2101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
2102cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
21035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2104cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage: {
2105cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
2106cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // SPIRV for Vulkan requires that sampled be 1 or 2 -- leaving the decision to runtime is unacceptable.
2107cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto dim = type.word(3);
2108cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto sampled = type.word(7);
21095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2110cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (dim == spv::DimSubpassData) {
2111cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
2112cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (dim == spv::DimBuffer) {
2113cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (sampled == 1) {
2114cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
2115cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
2116cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
2117cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
2118cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (sampled == 1) {
2119cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
2120cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                       descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
21215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
2122cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
21235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
21245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
21255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2126cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
2127cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
2128cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;  // Mismatch
21295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
21305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21324110a6be7a8a287d459475926985f71c27d01298Chris Forbesstatic bool require_feature(debug_report_data *report_data, VkBool32 feature, char const *feature_name) {
2133a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    if (!feature) {
21345b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2135cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
2136cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "Shader requires VkPhysicalDeviceFeatures::%s but is not "
2137cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "enabled on the device",
2138a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes                    feature_name)) {
21391b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            return true;
2140a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2141a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2142a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
21431b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return false;
2144a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2145a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
214659e12b842592a05706886ab852b767ba251d9467Chris Forbesstatic bool require_extension(debug_report_data *report_data, bool extension, char const *extension_name) {
21477b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes    if (!extension) {
21485b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
21497b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
21507b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    "Shader requires extension %s but is not "
21517b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    "enabled on the device",
21527b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    extension_name)) {
21531b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            return true;
21547b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes        }
21557b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes    }
21567b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes
21571b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return false;
21587b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes}
21597b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes
2160ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_shader_capabilities(layer_data *dev_data, shader_module const *src) {
21611b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
2162a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2163ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto report_data = dev_data->report_data;
2164ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto const & enabledFeatures = dev_data->enabled_features;
2165ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes
2166a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    for (auto insn : *src) {
2167a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        if (insn.opcode() == spv::OpCapability) {
2168a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            switch (insn.word(1)) {
2169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMatrix:
2170cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityShader:
2171cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInputAttachment:
2172cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampled1D:
2173cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImage1D:
2174cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledBuffer:
2175cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageBuffer:
2176cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageQuery:
2177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityDerivativeControl:
2178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // Always supported by a Vulkan 1.0 implementation -- no feature bits.
2179cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2180a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2181cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityGeometry:
21821b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.geometryShader, "geometryShader");
2183cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2184a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2185cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityTessellation:
21861b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.tessellationShader, "tessellationShader");
2187cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2188a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2189cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityFloat64:
21901b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderFloat64, "shaderFloat64");
2191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2192a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInt64:
21941b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderInt64, "shaderInt64");
2195cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2196a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityTessellationPointSize:
2198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityGeometryPointSize:
21991b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderTessellationAndGeometryPointSize,
2200cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderTessellationAndGeometryPointSize");
2201cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2202a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2203cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageGatherExtended:
22041b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderImageGatherExtended, "shaderImageGatherExtended");
2205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2206a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2207cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageMultisample:
22081b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderStorageImageMultisample,
2209cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageMultisample");
2210cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2211a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2212cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityUniformBufferArrayDynamicIndexing:
22131b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderUniformBufferArrayDynamicIndexing,
2214cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderUniformBufferArrayDynamicIndexing");
2215cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2216a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2217cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledImageArrayDynamicIndexing:
22181b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderSampledImageArrayDynamicIndexing,
2219cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderSampledImageArrayDynamicIndexing");
2220cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2221a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2222cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageBufferArrayDynamicIndexing:
22231b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderStorageBufferArrayDynamicIndexing,
2224cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageBufferArrayDynamicIndexing");
2225cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2226a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2227cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageArrayDynamicIndexing:
22281b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderStorageImageArrayDynamicIndexing,
2229cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageArrayDynamicIndexing");
2230cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2231a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2232cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityClipDistance:
22331b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderClipDistance, "shaderClipDistance");
2234cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2235a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2236cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityCullDistance:
22371b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderCullDistance, "shaderCullDistance");
2238cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2239a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2240cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageCubeArray:
22411b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.imageCubeArray, "imageCubeArray");
2242cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2243a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2244cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampleRateShading:
22451b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.sampleRateShading, "sampleRateShading");
2246cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2247a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySparseResidency:
22491b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderResourceResidency, "shaderResourceResidency");
2250cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2251a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2252cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMinLod:
22531b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderResourceMinLod, "shaderResourceMinLod");
2254cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2255a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2256cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledCubeArray:
22571b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.imageCubeArray, "imageCubeArray");
2258cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2259a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2260cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageMSArray:
22611b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderStorageImageMultisample,
2262cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageMultisample");
2263cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2264a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2265cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageExtendedFormats:
22661b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderStorageImageExtendedFormats,
2267cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageExtendedFormats");
2268cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2269a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2270cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInterpolationFunction:
22711b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.sampleRateShading, "sampleRateShading");
2272cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2273a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2274cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageReadWithoutFormat:
22751b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderStorageImageReadWithoutFormat,
2276cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageReadWithoutFormat");
2277cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2278a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2279cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageWriteWithoutFormat:
22801b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.shaderStorageImageWriteWithoutFormat,
2281cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageWriteWithoutFormat");
2282cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2283a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2284cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMultiViewport:
22851b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_feature(report_data, enabledFeatures.multiViewport, "multiViewport");
2286cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2287a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
22887b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                case spv::CapabilityDrawParameters:
22891b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_extension(report_data, dev_data->device_extensions.khr_shader_draw_parameters_enabled,
22907b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                                              VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME);
22917b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    break;
22927b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes
22932664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski                case spv::CapabilityGeometryShaderPassthroughNV:
22941b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_extension(report_data, dev_data->device_extensions.nv_geometry_shader_passthrough_enabled,
22952664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski                                              VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME);
22962664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski                    break;
22972664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski
2298bd546e41d3ab1deff04a593364d3522332df179eMark Lobodzinski                case spv::CapabilitySampleMaskOverrideCoverageNV:
22991b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_extension(report_data, dev_data->device_extensions.nv_sample_mask_override_coverage_enabled,
2300bd546e41d3ab1deff04a593364d3522332df179eMark Lobodzinski                                              VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME);
2301bd546e41d3ab1deff04a593364d3522332df179eMark Lobodzinski                    break;
2302bd546e41d3ab1deff04a593364d3522332df179eMark Lobodzinski
23036f82da9debd5cdeda59f388250b506c59e7d8d54Mark Lobodzinski                case spv::CapabilityShaderViewportIndexLayerNV:
23046f82da9debd5cdeda59f388250b506c59e7d8d54Mark Lobodzinski                case spv::CapabilityShaderViewportMaskNV:
23051b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_extension(report_data, dev_data->device_extensions.nv_viewport_array2_enabled,
23066f82da9debd5cdeda59f388250b506c59e7d8d54Mark Lobodzinski                                              VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME);
23076f82da9debd5cdeda59f388250b506c59e7d8d54Mark Lobodzinski                    break;
23086f82da9debd5cdeda59f388250b506c59e7d8d54Mark Lobodzinski
230968774dfa273ec153ae4e65f69cca6fb16b9309feMark Lobodzinski                case spv::CapabilitySubgroupBallotKHR:
23101b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_extension(report_data, dev_data->device_extensions.khr_subgroup_ballot_enabled,
231168774dfa273ec153ae4e65f69cca6fb16b9309feMark Lobodzinski                                              VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME);
231268774dfa273ec153ae4e65f69cca6fb16b9309feMark Lobodzinski                    break;
231368774dfa273ec153ae4e65f69cca6fb16b9309feMark Lobodzinski
2314ae17c7b673b9763c8e74bb70ed9e53b00aca8081Mark Lobodzinski                case spv::CapabilitySubgroupVoteKHR:
23151b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= require_extension(report_data, dev_data->device_extensions.khr_subgroup_vote_enabled,
2316ae17c7b673b9763c8e74bb70ed9e53b00aca8081Mark Lobodzinski                                              VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME);
2317ae17c7b673b9763c8e74bb70ed9e53b00aca8081Mark Lobodzinski                    break;
2318ae17c7b673b9763c8e74bb70ed9e53b00aca8081Mark Lobodzinski
2319cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
2320436434eba4d9f91016f313c8fb1525d76d7932fcMark Lobodzinski                    // Spirv-validator should catch these errors
2321cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2322a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            }
2323a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2324a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2325a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
23261b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
2327a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2328a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2329b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbesstatic uint32_t descriptor_type_to_reqs(shader_module const *module, uint32_t type_id) {
23302aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    auto type = module->get_def(type_id);
23312aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes
23322aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    while (true) {
23332aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        switch (type.opcode()) {
2334cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
2335cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
2336cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(2));
2337cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2338cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
2339cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(3));
2340cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2341cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage: {
2342cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = type.word(3);
2343cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto arrayed = type.word(5);
2344cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto msaa = type.word(6);
2345cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
2346cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                switch (dim) {
2347cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim1D:
2348cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_1D;
2349cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim2D:
2350cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return (msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE) |
2351cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               (arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_2D);
2352cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim3D:
2353cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return DESCRIPTOR_REQ_VIEW_TYPE_3D;
2354cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimCube:
2355cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_CUBE;
2356cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimSubpassData:
2357cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
2358cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    default:  // buffer, etc.
2359cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return 0;
2360cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
23612aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes            }
2362cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
2363cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return 0;
23642aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        }
23652aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    }
2366b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes}
2367b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes
2368cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool validate_pipeline_shader_stage(
2369ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    layer_data *dev_data, VkPipelineShaderStageCreateInfo const *pStage, PIPELINE_STATE *pipeline,
2370ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    shader_module **out_module, spirv_inst_iter *out_entrypoint) {
23711b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
2372ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto module_it = dev_data->shaderModuleMap.find(pStage->module);
237369f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes    auto module = *out_module = module_it->second.get();
2374ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto report_data = dev_data->report_data;
237578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
23761b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    if (!module->has_valid_spirv) return false;
2377c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski
237825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the entrypoint
237978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    auto entrypoint = *out_entrypoint = find_entrypoint(module, pStage->pName, pStage->stage);
238078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    if (entrypoint == module->end()) {
23815b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
23825b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski                    VALIDATION_ERROR_00510, "SC", "No entrypoint found named `%s` for stage %s. %s.", pStage->pName,
23834f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                    string_VkShaderStageFlagBits(pStage->stage), validation_error_map[VALIDATION_ERROR_00510])) {
23841b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            return true;  // no point continuing beyond here, any analysis is just going to be garbage.
238578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
238678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
238778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
238825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate shader capabilities against enabled device features
23891b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    skip |= validate_shader_capabilities(dev_data, module);
239078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
239125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Mark accessible ids
23923a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto accessible_ids = mark_accessible_ids(module, entrypoint);
239378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
239425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor set layout against what the entrypoint actually uses
23953a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto descriptor_uses = collect_interface_by_descriptor_slot(report_data, module, accessible_ids);
239678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
23972e0eca3d6fad72a29ae072e3895e29a2d2d66476Tobin Ehlis    auto pipelineLayout = pipeline->pipeline_layout;
2398ed399f66e0512ef077d0e0a7cb903248726d2424Chris Forbes
23991b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    skip |= validate_specialization_offsets(report_data, pStage);
24001b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    skip |= validate_push_constant_usage(report_data, &pipelineLayout.push_constant_ranges, module, accessible_ids, pStage->stage);
240178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
240225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor use
240378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    for (auto use : descriptor_uses) {
240478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        // While validating shaders capture which slots are used by the pipeline
2405bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &reqs = pipeline->active_slots[use.first.first][use.first.second];
2406b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes        reqs = descriptor_req(reqs | descriptor_type_to_reqs(module, use.second.type_id));
240778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
240825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Verify given pipelineLayout has requested setLayout with requested binding
2409c8268861aaa8f9c47920065d6323e4609e5081b0Tobin Ehlis        const auto &binding = get_descriptor_binding(&pipelineLayout, use.first);
241078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        unsigned required_descriptor_count;
241178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
241278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        if (!binding) {
24131b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
24141b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
24151b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
24161b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str());
241778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (~binding->stageFlags & pStage->stage) {
24181b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
24191b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC",
24201b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Shader uses descriptor slot %u.%u (used "
24211b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "as type `%s`) but descriptor not "
24221b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "accessible from stage %s",
24231b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
24241b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            string_VkShaderStageFlagBits(pStage->stage));
2425bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else if (!descriptor_type_match(module, use.second.type_id, binding->descriptorType, required_descriptor_count)) {
24261b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
24271b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
24281b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Type mismatch on descriptor slot "
24291b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "%u.%u (used as type `%s`) but "
24301b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "descriptor of type %s",
24311b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
24321b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            string_VkDescriptorType(binding->descriptorType));
243378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (binding->descriptorCount < required_descriptor_count) {
24341b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
24351b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
24361b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
24371b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            required_descriptor_count, use.first.first, use.first.second,
24381b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            describe_type(module, use.second.type_id).c_str(), binding->descriptorCount);
243978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
244078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
244178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
244225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate use of input attachments against subpass structure
2443c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    if (pStage->stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
244412b7fc342b53fbdd399aae4a85959e37685936acChris Forbes        auto input_attachment_uses = collect_interface_by_input_attachment_index(module, accessible_ids);
2445c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2446c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto rpci = pipeline->render_pass_ci.ptr();
2447c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto subpass = pipeline->graphicsPipelineCI.subpass;
2448c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2449c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        for (auto use : input_attachment_uses) {
2450c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            auto input_attachments = rpci->pSubpasses[subpass].pInputAttachments;
2451bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto index = (input_attachments && use.first < rpci->pSubpasses[subpass].inputAttachmentCount)
2452bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             ? input_attachments[use.first].attachment
2453bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             : VK_ATTACHMENT_UNUSED;
2454c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2455c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            if (index == VK_ATTACHMENT_UNUSED) {
24561b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
24571b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_MISSING_INPUT_ATTACHMENT, "SC",
24581b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Shader consumes input attachment index %d but not provided in subpass", use.first);
2459f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            } else if (!(get_format_type(rpci->pAttachments[index].format) & get_fundamental_type(module, use.second.type_id))) {
24601b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |=
24611b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2462eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                            SHADER_CHECKER_INPUT_ATTACHMENT_TYPE_MISMATCH, "SC",
2463bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Subpass input attachment %u format of %s does not match type used in shader `%s`", use.first,
24641b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            string_VkFormat(rpci->pAttachments[index].format), describe_type(module, use.second.type_id).c_str());
2465eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes            }
2466c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        }
2467c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    }
2468c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
24691b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
247078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes}
247178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
2472a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis// Validate that the shaders used by the given pipeline and store the active_slots
2473a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis//  that are actually used by the pipeline into pPipeline->active_slots
2474ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_and_capture_pipeline_shader_state(layer_data *dev_data, PIPELINE_STATE *pPipeline) {
24756660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->graphicsPipelineCI.ptr();
24765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
24775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
24785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module *shaders[5];
24805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(shaders, 0, sizeof(shaders));
24815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter entrypoints[5];
24825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(entrypoints, 0, sizeof(entrypoints));
24831b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
24845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
24866660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes        auto pStage = &pCreateInfo->pStages[i];
248778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        auto stage_id = get_shader_stage_id(pStage->stage);
24881b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_pipeline_shader_stage(dev_data, pStage, pPipeline, &shaders[stage_id], &entrypoints[stage_id]);
24895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2491d5365427feb4a6c16371ecb651afa37b89dabd96Chris Forbes    // if the shader stages are no good individually, cross-stage validation is pointless.
24921b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    if (skip) return true;
2493b7476f4c4998ae20e579bd2d134667b71acdbf91Chris Forbes
2494ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto vi = pCreateInfo->pVertexInputState;
24955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
24971b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_vi_consistency(dev_data->report_data, vi);
24985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2500c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[vertex_stage] && shaders[vertex_stage]->has_valid_spirv) {
25011b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_vi_against_vs_inputs(dev_data->report_data, vi, shaders[vertex_stage], entrypoints[vertex_stage]);
25025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
25035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
25045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
25055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
25065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
25075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!shaders[producer] && producer != fragment_stage) {
25085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        producer++;
25095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        consumer++;
25105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
25115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
25125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
25135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(shaders[producer]);
2514c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        if (shaders[consumer] && shaders[consumer]->has_valid_spirv && shaders[producer]->has_valid_spirv) {
25151b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= validate_interface_between_stages(dev_data->report_data, shaders[producer], entrypoints[producer],
2516bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[producer], shaders[consumer], entrypoints[consumer],
2517bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[consumer]);
25185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
25195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            producer = consumer;
25205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
25215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
25225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2523c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[fragment_stage] && shaders[fragment_stage]->has_valid_spirv) {
25241b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_fs_outputs_against_render_pass(dev_data->report_data, shaders[fragment_stage], entrypoints[fragment_stage],
25258da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                        pPipeline->render_pass_ci.ptr(), pCreateInfo->subpass);
25265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
25275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
25281b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
25295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
25305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2531ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_compute_pipeline(layer_data *dev_data, PIPELINE_STATE *pPipeline) {
25326660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->computePipelineCI.ptr();
253303857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
253403857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    shader_module *module;
253503857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    spirv_inst_iter entrypoint;
253603857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
2537ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    return validate_pipeline_shader_stage(dev_data, &pCreateInfo->stage, pPipeline, &module, &entrypoint);
253803857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes}
25395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Set node ptr for specified set or else NULL
25409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSet *GetSetNode(const layer_data *dev_data, VkDescriptorSet set) {
254151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto set_it = dev_data->setMap.find(set);
254251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (set_it == dev_data->setMap.end()) {
25435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
25445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2545104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return set_it->second;
25465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
25475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2548eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// For given pipeline, return number of MSAA samples, or one if MSAA disabled
25494c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic VkSampleCountFlagBits getNumSamples(PIPELINE_STATE const *pipe) {
2550ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    if (pipe->graphicsPipelineCI.pMultisampleState != NULL &&
2551ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pipe->graphicsPipelineCI.pMultisampleState->sType) {
2552eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        return pipe->graphicsPipelineCI.pMultisampleState->rasterizationSamples;
2553eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2554eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return VK_SAMPLE_COUNT_1_BIT;
2555eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2556eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
2557bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void list_bits(std::ostream &s, uint32_t bits) {
2558b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    for (int i = 0; i < 32 && bits; i++) {
2559b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        if (bits & (1 << i)) {
2560b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            s << i;
2561b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            bits &= ~(1 << i);
2562b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (bits) {
2563b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                s << ",";
2564b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            }
2565b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        }
2566b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    }
2567b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes}
2568b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
2569eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// Validate draw-time state related to the PSO
257051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidatePipelineDrawtimeState(layer_data const *dev_data, LAST_BOUND_STATE const &state, const GLOBAL_CB_NODE *pCB,
25714c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                          PIPELINE_STATE const *pPipeline) {
25723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
257329d196e071b2dc1db47702085469396f2b956820Chris Forbes
2574d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen    // Verify vertex binding
257529d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (pPipeline->vertexBindingDescriptions.size() > 0) {
257629d196e071b2dc1db47702085469396f2b956820Chris Forbes        for (size_t i = 0; i < pPipeline->vertexBindingDescriptions.size(); i++) {
2577312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            auto vertex_binding = pPipeline->vertexBindingDescriptions[i].binding;
2578312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            if ((pCB->currentDrawData.buffers.size() < (vertex_binding + 1)) ||
2579312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis                (pCB->currentDrawData.buffers[vertex_binding] == VK_NULL_HANDLE)) {
25803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
2581df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2582df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2583cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "The Pipeline State Object (0x%" PRIxLEAST64
2584cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            ") expects that this Command Buffer's vertex binding Index %u "
2585cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct "
2586cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "at index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
2587cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            (uint64_t)state.pipeline_state->pipeline, vertex_binding, i, vertex_binding);
258829d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
258929d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
259029d196e071b2dc1db47702085469396f2b956820Chris Forbes    } else {
259158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        if (!pCB->currentDrawData.buffers.empty() && !pCB->vertex_buffer_used) {
25923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
25933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(pCB->commandBuffer),
25943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
25953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Vertex buffers are bound to command buffer (0x%p"
25963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") but no vertex buffers are attached to this Pipeline State Object (0x%" PRIxLEAST64 ").",
25973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            pCB->commandBuffer, (uint64_t)state.pipeline_state->pipeline);
259829d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
259929d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
260029d196e071b2dc1db47702085469396f2b956820Chris Forbes    // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
260129d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip check if rasterization is disabled or there is no viewport.
260229d196e071b2dc1db47702085469396f2b956820Chris Forbes    if ((!pPipeline->graphicsPipelineCI.pRasterizationState ||
260329d196e071b2dc1db47702085469396f2b956820Chris Forbes         (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) &&
260429d196e071b2dc1db47702085469396f2b956820Chris Forbes        pPipeline->graphicsPipelineCI.pViewportState) {
260529d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
260629d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
2607b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
260829d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynViewport) {
2609b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredViewportsMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->viewportCount) - 1;
2610b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingViewportMask = ~pCB->viewportMask & requiredViewportsMask;
2611b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingViewportMask) {
2612b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2613b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic viewport(s) ";
2614b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingViewportMask);
2615d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetViewport().";
26163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
26173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
261829d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
261929d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
2620b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
262129d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynScissor) {
2622b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredScissorMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->scissorCount) - 1;
2623b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingScissorMask = ~pCB->scissorMask & requiredScissorMask;
2624b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingScissorMask) {
2625b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2626b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic scissor(s) ";
2627b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingScissorMask);
2628d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetScissor().";
26293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
26303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
263129d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
263229d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
263329d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
263429d196e071b2dc1db47702085469396f2b956820Chris Forbes
263529d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Verify that any MSAA request in PSO matches sample# in bound FB
263629d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip the check if rasterization is disabled.
263729d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
263829d196e071b2dc1db47702085469396f2b956820Chris Forbes        (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
263929d196e071b2dc1db47702085469396f2b956820Chris Forbes        VkSampleCountFlagBits pso_num_samples = getNumSamples(pPipeline);
264029d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (pCB->activeRenderPass) {
2641fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes            auto const render_pass_info = pCB->activeRenderPass->createInfo.ptr();
264229d196e071b2dc1db47702085469396f2b956820Chris Forbes            const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass];
264329d196e071b2dc1db47702085469396f2b956820Chris Forbes            uint32_t i;
264476957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            unsigned subpass_num_samples = 0;
26450a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
264629d196e071b2dc1db47702085469396f2b956820Chris Forbes            for (i = 0; i < subpass_desc->colorAttachmentCount; i++) {
264776957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pColorAttachments[i].attachment;
264876957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                if (attachment != VK_ATTACHMENT_UNUSED)
264976957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                    subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
265029d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
26510a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
265276957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            if (subpass_desc->pDepthStencilAttachment &&
265376957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
265476957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
265576957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
265629d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
2657eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
26580dc3fd4e57b8531638781daa01a2fb5d1048a6fbJamie Madill            if (subpass_num_samples && static_cast<unsigned>(pso_num_samples) != subpass_num_samples) {
26593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
26603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH,
26613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "DS", "Num samples mismatch! At draw-time in Pipeline (0x%" PRIxLEAST64
26623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                      ") with %u samples while current RenderPass (0x%" PRIxLEAST64 ") w/ %u samples!",
26633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                reinterpret_cast<const uint64_t &>(pPipeline->pipeline), pso_num_samples,
26643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                reinterpret_cast<const uint64_t &>(pCB->activeRenderPass->renderPass), subpass_num_samples);
2665eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young            }
266629d196e071b2dc1db47702085469396f2b956820Chris Forbes        } else {
26673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
26683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
26693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "No active render pass found at draw-time in Pipeline (0x%" PRIxLEAST64 ")!",
26703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline));
2671eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        }
2672eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2673528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    // Verify that PSO creation renderPass is compatible with active renderPass
2674528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    if (pCB->activeRenderPass) {
2675528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        std::string err_string;
2676a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if ((pCB->activeRenderPass->renderPass != pPipeline->graphicsPipelineCI.renderPass) &&
267751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(), pPipeline->render_pass_ci.ptr(),
2678528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                                             err_string)) {
2679528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            // renderPass that PSO was created with must be compatible with active renderPass that PSO is being used with
26803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
26813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE,
26823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "DS", "At Draw time the active render pass (0x%" PRIxLEAST64
26833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                  ") is incompatible w/ gfx pipeline "
26843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                  "(0x%" PRIxLEAST64 ") that was created w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
26853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(pCB->activeRenderPass->renderPass),
26863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t const &>(pPipeline->pipeline),
26873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->graphicsPipelineCI.renderPass), err_string.c_str());
2688528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        }
2689c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes
2690c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        if (pPipeline->graphicsPipelineCI.subpass != pCB->activeSubpass) {
26913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
26923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t const &>(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE,
26933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "DS", "Pipeline was built for subpass %u but used in subpass %u", pPipeline->graphicsPipelineCI.subpass,
26943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            pCB->activeSubpass);
2695c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        }
2696528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    }
269729d196e071b2dc1db47702085469396f2b956820Chris Forbes    // TODO : Add more checks here
269829d196e071b2dc1db47702085469396f2b956820Chris Forbes
26993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
2700eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2701eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
27025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate overall state at the time of a draw call
270351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const bool indexed,
27044f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              const VkPipelineBindPoint bind_point, const char *function,
27054f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
2706e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
27071c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_node->lastBound[bind_point];
27084c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
270922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    if (nullptr == pPipe) {
271022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        result |= log_msg(
2711df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2712df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            reinterpret_cast<uint64_t>(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_PIPELINE, "DS",
271322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            "At Draw/Dispatch time no valid VkPipeline is bound! This is illegal. Please bind one with vkCmdBindPipeline().");
271422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        // Early return as any further checks below will be busted w/o a pipeline
2715cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (result) return true;
271622fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
27173d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // First check flag states
27181c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point)
271951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        result = validate_draw_state_flags(dev_data, cb_node, pPipe, indexed, msg_code);
27207a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis
27215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Now complete other state checks
272269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
272322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        string errorString;
272469b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        auto pipeline_layout = pPipe->pipeline_layout;
2725169c4506062f06d6676eb4da3c9e0437d1d9d659Chris Forbes
27261c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
27271c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
272822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            // If valid set is not bound throw an error
272922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
2730df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                result |= log_msg(
2731df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2732df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    reinterpret_cast<uint64_t>(cb_node->commandBuffer), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS",
2733df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    "VkPipeline 0x%" PRIxLEAST64 " uses set #%u but that set is not bound.", (uint64_t)pPipe->pipeline, setIndex);
273412b7fc342b53fbdd399aae4a85959e37685936acChris Forbes            } else if (!verify_set_layout_compatibility(state.boundDescriptorSets[setIndex], &pipeline_layout, setIndex,
273569b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                                        errorString)) {
273669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                // Set is bound but not compatible w/ overlapping pipeline_layout from PSO
273771511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                VkDescriptorSet setHandle = state.boundDescriptorSets[setIndex]->GetSet();
273822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                result |=
273951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
274022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                            (uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
2741414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            "VkDescriptorSet (0x%" PRIxLEAST64
2742414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") bound as set #%u is not compatible with overlapping VkPipelineLayout 0x%" PRIxLEAST64 " due to: %s",
274369b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                            reinterpret_cast<uint64_t &>(setHandle), setIndex, reinterpret_cast<uint64_t &>(pipeline_layout.layout),
274469b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                            errorString.c_str());
2745cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {  // Valid set is bound and layout compatible, validate that it's updated
274622fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Pull the set node
27471c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
2748aa21bc3b3c5c7adfeb488fc80bdcb339d63615b8Tobin Ehlis                // Gather active bindings
2749ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                std::unordered_set<uint32_t> active_bindings;
27501c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                for (auto binding : set_binding_pair.second) {
2751ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                    active_bindings.insert(binding.first);
2752aa21bc3b3c5c7adfeb488fc80bdcb339d63615b8Tobin Ehlis                }
275322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Make sure set has been updated if it has no immutable samplers
275422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                //  If it has immutable samplers, we'll flag error later as needed depending on binding
27551c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                if (!descriptor_set->IsUpdated()) {
2756ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                    for (auto binding : active_bindings) {
27571c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                        if (!descriptor_set->GetImmutableSamplerPtrFromBinding(binding)) {
275851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2759cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)descriptor_set->GetSet(),
2760cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
2761cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              "Descriptor Set 0x%" PRIxLEAST64
2762cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              " bound but was never updated. It is now being used to draw so "
2763cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              "this will result in undefined behavior.",
2764cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              (uint64_t)descriptor_set->GetSet());
2765fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        }
27665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
27675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
27687433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                // Validate the draw-time state for this descriptor set
27697433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                std::string err_str;
27700db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                if (!descriptor_set->ValidateDrawState(set_binding_pair.second, state.dynamicOffsets[setIndex], cb_node, function,
27710db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                                                       &err_str)) {
27721c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    auto set = descriptor_set->GetSet();
27730db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                    result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
27740db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                                      VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, reinterpret_cast<const uint64_t &>(set),
27750db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                                      __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
27760db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                                      "Descriptor set 0x%" PRIxLEAST64 " encountered the following validation error at %s time: %s",
27770db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                                      reinterpret_cast<const uint64_t &>(set), function, err_str.c_str());
27787433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                }
27795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
278022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        }
278122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
2782eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
2783eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    // Check general pipeline state that needs to be validated at drawtime
278451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) result |= ValidatePipelineDrawtimeState(dev_data, state, cb_node, pPipe);
2785eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
27865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
27875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
27885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
278951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const VkPipelineBindPoint bind_point) {
27901c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_state->lastBound[bind_point];
2791ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
2792ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
27931c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
27941c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
2795ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Pull the set node
27961c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
2797ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Bind this set and its active descriptor resources to the command buffer
27981c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->BindCommandBuffer(cb_state, set_binding_pair.second);
27997433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis            // For given active slots record updated images & buffers
28001c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->GetStorageUpdates(set_binding_pair.second, &cb_state->updateBuffers, &cb_state->updateImages);
2801ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis        }
2802ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    }
280358b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (pPipe->vertexBindingDescriptions.size() > 0) {
280458b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        cb_state->vertex_buffer_used = true;
280558b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
2806ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis}
2807ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis
2808a27508babf63d50aea75883a3702979193c23683Mark Young// Validate HW line width capabilities prior to setting requested line width.
280906727c7f56d1080aff506a9ae1ae9d8c174b3e9dMark Lobodzinskistatic bool verifyLineWidth(layer_data *dev_data, DRAW_STATE_ERROR dsError, VulkanObjectType object_type, const uint64_t &target,
281006727c7f56d1080aff506a9ae1ae9d8c174b3e9dMark Lobodzinski                            float lineWidth) {
28113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
2812a27508babf63d50aea75883a3702979193c23683Mark Young
2813a27508babf63d50aea75883a3702979193c23683Mark Young    // First check to see if the physical device supports wide lines.
281451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if ((VK_FALSE == dev_data->enabled_features.wideLines) && (1.0f != lineWidth)) {
28153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object_type], target, __LINE__,
28163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        dsError, "DS",
28173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Attempt to set lineWidth to %f but physical device wideLines feature "
28183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "not supported/enabled so lineWidth must be 1.0f!",
28193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        lineWidth);
2820a27508babf63d50aea75883a3702979193c23683Mark Young    } else {
2821a27508babf63d50aea75883a3702979193c23683Mark Young        // Otherwise, make sure the width falls in the valid range.
282251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if ((dev_data->phys_dev_properties.properties.limits.lineWidthRange[0] > lineWidth) ||
282351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            (dev_data->phys_dev_properties.properties.limits.lineWidthRange[1] < lineWidth)) {
28243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object_type], target,
28253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, dsError, "DS",
28263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Attempt to set lineWidth to %f but physical device limits line width "
28273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "to between [%f, %f]!",
28283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            lineWidth, dev_data->phys_dev_properties.properties.limits.lineWidthRange[0],
28293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            dev_data->phys_dev_properties.properties.limits.lineWidthRange[1]);
2830a27508babf63d50aea75883a3702979193c23683Mark Young        }
2831a27508babf63d50aea75883a3702979193c23683Mark Young    }
2832a27508babf63d50aea75883a3702979193c23683Mark Young
28333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
2834a27508babf63d50aea75883a3702979193c23683Mark Young}
2835a27508babf63d50aea75883a3702979193c23683Mark Young
28365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify that create state for a pipeline is valid
283751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verifyPipelineCreateState(layer_data *dev_data, std::vector<PIPELINE_STATE *> pPipelines, int pipelineIndex) {
28383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
28395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
28404c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipeline = pPipelines[pipelineIndex];
28415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
28425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If create derivative bit is set, check that we've specified a base
28435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // pipeline correctly, and that the base pipeline was created to allow
28445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // derivatives.
28455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
28464c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pBasePipeline = nullptr;
28475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^
28485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis              (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) {
2849f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt            // This check is a superset of VALIDATION_ERROR_00526 and VALIDATION_ERROR_00528
28503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
28513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE,
28523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "DS", "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified");
28535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) {
28545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) {
28553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
2856df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2857df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_00518, "DS",
2858f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline. %s",
2859f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            validation_error_map[VALIDATION_ERROR_00518]);
28605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
28615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex];
28625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
28635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
286451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            pBasePipeline = getPipelineState(dev_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
28655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
28665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
28675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
28683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
28693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE,
28703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "DS", "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives.");
28715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
28725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
28745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
2875fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const safe_VkPipelineColorBlendStateCreateInfo *color_blend_state = pPipeline->graphicsPipelineCI.pColorBlendState;
28769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto const render_pass_info = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass)->createInfo.ptr();
2877fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pPipeline->graphicsPipelineCI.subpass];
2878fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        if (color_blend_state->attachmentCount != subpass_desc->colorAttachmentCount) {
28793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(
288051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2881fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02109, "DS",
2882fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                "vkCreateGraphicsPipelines(): Render pass (0x%" PRIxLEAST64
2883fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                ") subpass %u has colorAttachmentCount of %u which doesn't match the pColorBlendState->attachmentCount of %u. %s",
2884fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                reinterpret_cast<const uint64_t &>(pPipeline->graphicsPipelineCI.renderPass), pPipeline->graphicsPipelineCI.subpass,
2885fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                subpass_desc->colorAttachmentCount, color_blend_state->attachmentCount,
2886fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                validation_error_map[VALIDATION_ERROR_02109]);
2887fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        }
288851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.independentBlend) {
28893d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (pPipeline->attachments.size() > 1) {
289026c548826ff0f83d12c769b51e7d6f76d1265c0eChris Forbes                VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0];
2891c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
289206811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // Quoting the spec: "If [the independent blend] feature is not enabled, the VkPipelineColorBlendAttachmentState
289306811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // settings for all color attachments must be identical." VkPipelineColorBlendAttachmentState contains
289406811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // only attachment state, so memcmp is best suited for the comparison
289506811df0256552cd7da9d7297672af377463fc4aMark Mueller                    if (memcmp(static_cast<const void *>(pAttachments), static_cast<const void *>(&pAttachments[i]),
289606811df0256552cd7da9d7297672af377463fc4aMark Mueller                               sizeof(pAttachments[0]))) {
28973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        skip |=
2898df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2899df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_01532, "DS",
2900df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "Invalid Pipeline CreateInfo: If independent blend feature not "
2901df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "enabled, all elements of pAttachments must be identical. %s",
2902df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    validation_error_map[VALIDATION_ERROR_01532]);
290306811df0256552cd7da9d7297672af377463fc4aMark Mueller                        break;
2904c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                    }
29055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
29065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
29075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
290851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.logicOp && (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) {
29093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
2910df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2911df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_01533, "DS",
2912f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE. %s",
2913f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        validation_error_map[VALIDATION_ERROR_01533]);
29145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
29155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
29165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2917a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis    // Ensure the subpass index is valid. If not, then validate_and_capture_pipeline_shader_state
29185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // produces nonsense errors that confuse users. Other layers should already
29195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // emit errors for renderpass being invalid.
29209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto renderPass = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass);
2921fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    if (renderPass && pPipeline->graphicsPipelineCI.subpass >= renderPass->createInfo.subpassCount) {
29223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
29233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02122, "DS",
29243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: Subpass index %u "
29253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "is out of range for this renderpass (0..%u). %s",
29263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pPipeline->graphicsPipelineCI.subpass, renderPass->createInfo.subpassCount - 1,
29273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_02122]);
29285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
29295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
29301b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    if (!GetDisables(dev_data)->shader_validation && validate_and_capture_pipeline_shader_state(dev_data, pPipeline)) {
29313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = true;
29325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
293352156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    // Each shader's stage must be unique
293452156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    if (pPipeline->duplicate_shaders) {
293552156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        for (uint32_t stage = VK_SHADER_STAGE_VERTEX_BIT; stage & VK_SHADER_STAGE_ALL_GRAPHICS; stage <<= 1) {
293652156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            if (pPipeline->duplicate_shaders & stage) {
29373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
2938df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2939df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE,
2940df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "DS", "Invalid Pipeline CreateInfo State: Multiple shaders provided for stage %s",
2941df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            string_VkShaderStageFlagBits(VkShaderStageFlagBits(stage)));
294252156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            }
294352156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        }
294452156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    }
29455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VS is required
29465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
29473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
2948df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2949df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_00532, "DS",
2950df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    "Invalid Pipeline CreateInfo State: Vertex Shader required. %s", validation_error_map[VALIDATION_ERROR_00532]);
29515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
29525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Either both or neither TC/TE shaders should be defined
2953f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if ((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) &&
2954f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        !(pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
29553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
29563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_00534, "DS",
29573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
29583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_00534]);
2959f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
2960f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) &&
2961f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
29623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
29633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_00535, "DS",
29643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
29653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_00535]);
29665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
29675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Compute shaders should be specified independent of Gfx shaders
2968f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) {
29693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
29703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_00533, "DS",
29713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline. %s",
29723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_00533]);
29735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
29745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
29755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Mismatching primitive topology and tessellation fails graphics pipeline creation.
29765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) &&
2977ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        (!pPipeline->graphicsPipelineCI.pInputAssemblyState ||
2978ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         pPipeline->graphicsPipelineCI.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
29793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
29803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02099, "DS",
29813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: "
29823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
29833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "topology for tessellation pipelines. %s",
29843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_02099]);
29855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2986ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pInputAssemblyState &&
2987ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        pPipeline->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
29885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
29893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
29903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02100, "DS",
29913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Invalid Pipeline CreateInfo State: "
29923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
29933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "topology is only valid for tessellation pipelines. %s",
29943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_02100]);
29955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
29965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2997f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
2998f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->graphicsPipelineCI.pTessellationState &&
2999f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        ((pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints == 0) ||
3000f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt         (pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints >
300151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis          dev_data->phys_dev_properties.properties.limits.maxTessellationPatchSize))) {
30023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
30033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_01426, "DS",
30043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: "
30053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
30063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "topology used with patchControlPoints value %u."
30073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        " patchControlPoints should be >0 and <=%u. %s",
30083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints,
30093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        dev_data->phys_dev_properties.properties.limits.maxTessellationPatchSize,
30103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_01426]);
3011f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
3012f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
30136b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen    // If a rasterization state is provided...
3014a27508babf63d50aea75883a3702979193c23683Mark Young    if (pPipeline->graphicsPipelineCI.pRasterizationState) {
30156b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // Make sure that the line width conforms to the HW.
3016a27508babf63d50aea75883a3702979193c23683Mark Young        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_LINE_WIDTH)) {
30173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, kVulkanObjectTypePipeline,
30183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    reinterpret_cast<uint64_t const &>(pPipeline->pipeline),
30193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    pPipeline->graphicsPipelineCI.pRasterizationState->lineWidth);
3020a27508babf63d50aea75883a3702979193c23683Mark Young        }
30215dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes
302258c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski        if ((pPipeline->graphicsPipelineCI.pRasterizationState->depthClampEnable == VK_TRUE) &&
302358c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski            (!dev_data->enabled_features.depthClamp)) {
30243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
30253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_01455, "DS",
30263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCreateGraphicsPipelines(): the depthClamp device feature is disabled: the depthClampEnable "
30273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "member of the VkPipelineRasterizationStateCreateInfo structure must be set to VK_FALSE. %s",
30283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_01455]);
302958c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski        }
303058c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski
3031434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_BIAS) &&
3032434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            (pPipeline->graphicsPipelineCI.pRasterizationState->depthBiasClamp != 0.0) &&
3033434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            (!dev_data->enabled_features.depthBiasClamp)) {
30343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
30353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
30363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCreateGraphicsPipelines(): the depthBiasClamp device feature is disabled: the depthBiasClamp "
30373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "member of the VkPipelineRasterizationStateCreateInfo structure must be set to 0.0 unless the "
30383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "VK_DYNAMIC_STATE_DEPTH_BIAS dynamic state is enabled");
3039434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
3040434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski
30416b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // If rasterization is enabled...
30426b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        if (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE) {
30436b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            auto subpass_desc = renderPass ? &renderPass->createInfo.pSubpasses[pPipeline->graphicsPipelineCI.subpass] : nullptr;
30446b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
3045148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski            if ((pPipeline->graphicsPipelineCI.pMultisampleState->alphaToOneEnable == VK_TRUE) &&
3046148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski                (!dev_data->enabled_features.alphaToOne)) {
30473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
30483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_01464, "DS",
30493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "vkCreateGraphicsPipelines(): the alphaToOne device feature is disabled: the alphaToOneEnable "
30503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "member of the VkPipelineMultisampleStateCreateInfo structure must be set to VK_FALSE. %s",
30513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                validation_error_map[VALIDATION_ERROR_01464]);
3052148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski            }
3053148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski
30546b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            // If subpass uses a depth/stencil attachment, pDepthStencilState must be a pointer to a valid structure
30556b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            if (subpass_desc && subpass_desc->pDepthStencilAttachment &&
30566b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
30576b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                if (!pPipeline->graphicsPipelineCI.pDepthStencilState) {
30583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
30593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02115, "DS",
30603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Invalid Pipeline CreateInfo State: pDepthStencilState is NULL when rasterization is "
30613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "enabled and subpass uses a depth/stencil attachment. %s",
30623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    validation_error_map[VALIDATION_ERROR_02115]);
30639580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski
30649580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                } else if ((pPipeline->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE) &&
30659580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                           (!dev_data->enabled_features.depthBounds)) {
30663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
3067df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3068df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
30699580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                        "vkCreateGraphicsPipelines(): the depthBounds device feature is disabled: the depthBoundsTestEnable "
30709580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                        "member of the VkPipelineDepthStencilStateCreateInfo structure must be set to VK_FALSE.");
30716b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                }
30725dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes            }
3073326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen
3074326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            // If subpass uses color attachments, pColorBlendState must be valid pointer
3075326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            if (subpass_desc) {
3076326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                uint32_t color_attachment_count = 0;
3077326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; ++i) {
3078326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    if (subpass_desc->pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
3079326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                        ++color_attachment_count;
3080326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    }
3081326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
3082326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                if (color_attachment_count > 0 && pPipeline->graphicsPipelineCI.pColorBlendState == nullptr) {
30833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
30843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02116, "DS",
30853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Invalid Pipeline CreateInfo State: pColorBlendState is NULL when rasterization is "
30863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "enabled and subpass uses color attachments. %s",
30873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    validation_error_map[VALIDATION_ERROR_02116]);
3088326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
3089326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            }
30905dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes        }
30915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
30926b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
30933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
30945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free the Pipeline nodes
309751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePipelines(layer_data *dev_data) {
309851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->pipelineMap.size() <= 0) return;
309951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto &pipe_map_pair : dev_data->pipelineMap) {
3100ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        delete pipe_map_pair.second;
31015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
310251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->pipelineMap.clear();
31035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
31045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
31055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Block of code at start here specifically for managing/tracking DSs
31065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
31075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Pool node ptr for specified pool or else NULL
31089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDESCRIPTOR_POOL_STATE *GetDescriptorPoolState(const layer_data *dev_data, const VkDescriptorPool pool) {
3109bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    auto pool_it = dev_data->descriptorPoolMap.find(pool);
3110bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    if (pool_it == dev_data->descriptorPoolMap.end()) {
31115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
31125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3113bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    return pool_it->second;
31145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
31155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
31165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
31175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// func_str is the name of the calling function
3118e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return false if no errors occur
3119e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
31200dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlisstatic bool validateIdleDescriptorSet(const layer_data *dev_data, VkDescriptorSet set, std::string func_str) {
3121cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.idle_descriptor_set) return false;
31223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
31230dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    auto set_node = dev_data->setMap.find(set);
31240dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    if (set_node == dev_data->setMap.end()) {
31253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
31263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        (uint64_t)(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
31273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.", func_str.c_str(),
31283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        (uint64_t)(set));
31295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
31301c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis        // TODO : This covers various error cases so should pass error enum into this function and use passed in enum here
31315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (set_node->second->in_use.load()) {
31323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
31333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            (uint64_t)(set), __LINE__, VALIDATION_ERROR_00919, "DS",
31343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that is in use by a command buffer. %s",
31353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            func_str.c_str(), (uint64_t)(set), validation_error_map[VALIDATION_ERROR_00919]);
31365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
31375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
31395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
3140f80bf38f4fb3f177b3e1be11b7b1c5edcdbf7d9bChris Forbes
3141e6651096ed8f07840447783c66827cc16d659a49Tobin Ehlis// Remove set from setMap and delete the set
31429dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlisstatic void freeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
31439dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    dev_data->setMap.erase(descriptor_set->GetSet());
31449dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    delete descriptor_set;
31459dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis}
31465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all DS Pools including their Sets & related sub-structs
31475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
314851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePools(layer_data *dev_data) {
314951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->descriptorPoolMap.size() <= 0) return;
315051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto ii = dev_data->descriptorPoolMap.begin(); ii != dev_data->descriptorPoolMap.end(); ++ii) {
3151c5f47f0a54e14c47d402aeabc6498d981ecda9ccTobin Ehlis        // Remove this pools' sets from setMap and delete them
3152cb9ce9e05b8e939d3da35c64997c70049877f4feTobin Ehlis        for (auto ds : (*ii).second->sets) {
315351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            freeDescriptorSet(dev_data, ds);
31545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
3155f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis        (*ii).second->sets.clear();
31565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
315751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->descriptorPoolMap.clear();
31585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
31595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
316051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void clearDescriptorPool(layer_data *dev_data, const VkDevice device, const VkDescriptorPool pool,
31615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                VkDescriptorPoolResetFlags flags) {
31629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pPool = GetDescriptorPoolState(dev_data, pool);
3163de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // TODO: validate flags
3164de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // For every set off of this pool, clear it, remove from setMap, and free cvdescriptorset::DescriptorSet
3165de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (auto ds : pPool->sets) {
316651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        freeDescriptorSet(dev_data, ds);
3167de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    }
3168de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->sets.clear();
3169de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // Reset available count for each type and available sets for this pool
3170de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
3171de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis        pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
31725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3173de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->availableSets = pPool->maxSets;
31745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
31755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
31765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For given CB object, fetch associated CB Node from map
31779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *dev_data, const VkCommandBuffer cb) {
317851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->commandBufferMap.find(cb);
317951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->commandBufferMap.end()) {
31805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
31815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31825121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbes    return it->second;
31835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
31845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
318529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis// If a renderpass is active, verify that the given command type is appropriate for current subpass state
318629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlisbool ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
3187cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pCB->activeRenderPass) return false;
31883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3189d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis    if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS &&
3190d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis        (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS)) {
31913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
31923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
31933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Commands cannot be called in a subpass using secondary command buffers.");
31945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) {
31953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
31963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
31973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdExecuteCommands() cannot be called in a subpass using inline commands.");
31985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
32005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3202baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardtbool ValidateCmdQueueFlags(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const char *caller_name, VkQueueFlags required_flags,
3203baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           UNIQUE_VALIDATION_ERROR_CODE error_code) {
3204baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    auto pool = GetCommandPoolNode(dev_data, cb_node->createInfo.commandPool);
3205baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    if (pool) {
3206baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        VkQueueFlags queue_flags = dev_data->phys_dev_properties.queue_family_properties[pool->queueFamilyIndex].queueFlags;
3207baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        if (!(required_flags & queue_flags)) {
3208baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            string required_flags_string;
3209baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            for (auto flag : {VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT}) {
3210baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                if (flag & required_flags) {
3211baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    if (required_flags_string.size()) {
3212baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                        required_flags_string += " or ";
3213baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    }
3214baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    required_flags_string += string_VkQueueFlagBits(flag);
3215baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                }
3216baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            }
3217baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3218baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           reinterpret_cast<uint64_t>(cb_node->commandBuffer), __LINE__, error_code, "DS",
3219baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           "Cannot call %s on a command buffer allocated from a pool without %s capabilities. %s.", caller_name,
3220baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           required_flags_string.c_str(), validation_error_map[error_code]);
3221baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        }
3222baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    }
32235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
32245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3226ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinskistatic bool ReportInvalidCommandBuffer(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source) {
3227ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    bool skip = false;
3228ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    for (auto obj : cb_state->broken_bindings) {
32297a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        const char *type_str = object_string[obj.type];
3230ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        // Descriptor sets are a special case that can be either destroyed or updated to invalidate a CB
32317a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        const char *cause_str = (obj.type == kVulkanObjectTypeDescriptorSet) ? "destroyed or updated" : "destroyed";
3232ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3233ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        reinterpret_cast<uint64_t &>(cb_state->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
3234ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        "You are adding %s to command buffer 0x%p that is invalid because bound %s 0x%" PRIxLEAST64 " was %s.",
3235ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        call_source, cb_state->commandBuffer, type_str, obj.handle, cause_str);
3236ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    }
3237ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    return skip;
3238ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski}
3239ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
3240623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Validate the given command being added to the specified cmd buffer, flagging errors if CB is not in the recording state or if
3241623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// there's an issue with the Cmd ordering
3242946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskibool ValidateCmd(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd, const char *caller_name) {
324333f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes    switch (cb_state->state) {
324433f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        case CB_RECORDING:
324533f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return ValidateCmdSubpassState(dev_data, cb_state, cmd);
324633f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes
324733f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        case CB_INVALID:
324833f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return ReportInvalidCommandBuffer(dev_data, cb_state, caller_name);
324933f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes
325033f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        default:
325133f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
325233f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes                           reinterpret_cast<uint64_t &>(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS",
325333f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes                           "You must call vkBeginCommandBuffer() before this call to %s", caller_name);
32545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
32555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
325629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis
32571ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlisvoid UpdateCmdBufferLastCmd(GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd) {
325829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    if (cb_state->state == CB_RECORDING) {
325929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        cb_state->last_cmd = cmd;
326029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    }
326129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis}
32627e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For given object struct return a ptr of BASE_NODE type for its wrapping struct
32637e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin EhlisBASE_NODE *GetStateStructPtrFromObject(layer_data *dev_data, VK_OBJECT object_struct) {
32647e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_ptr = nullptr;
32657e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    switch (object_struct.type) {
3266ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDescriptorSet: {
32679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(object_struct.handle));
3268cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3269cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3270ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeSampler: {
32719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSamplerState(dev_data, reinterpret_cast<VkSampler &>(object_struct.handle));
3272cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3273cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3274ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeQueryPool: {
32759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(object_struct.handle));
3276cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3277cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3278ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypePipeline: {
3279cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getPipelineState(dev_data, reinterpret_cast<VkPipeline &>(object_struct.handle));
3280cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3281cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3282ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeBuffer: {
32839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object_struct.handle));
3284cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3285cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3286ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeBufferView: {
32879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(object_struct.handle));
3288cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3289cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3290ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeImage: {
32919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageState(dev_data, reinterpret_cast<VkImage &>(object_struct.handle));
3292cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3293cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3294ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeImageView: {
32959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageViewState(dev_data, reinterpret_cast<VkImageView &>(object_struct.handle));
3296cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3297cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3298ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeEvent: {
32999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetEventNode(dev_data, reinterpret_cast<VkEvent &>(object_struct.handle));
3300cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3301cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3302ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDescriptorPool: {
33039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(object_struct.handle));
3304cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3305cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3306ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeCommandPool: {
33079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(object_struct.handle));
3308cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3309cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3310ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeFramebuffer: {
33119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(object_struct.handle));
3312cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3313cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3314ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeRenderPass: {
33159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(object_struct.handle));
3316cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3317cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3318ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDeviceMemory: {
33199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(object_struct.handle));
3320cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3321cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3322cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
3323cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO : Any other objects to be handled here?
3324cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            assert(0);
3325cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3326bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis    }
33277e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    return base_ptr;
33287e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
33297e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis
33307e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// Tie the VK_OBJECT to the cmd buffer which includes:
33317e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add object_binding to cmd buffer
33327e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add cb_binding to object
33337e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void addCommandBufferBinding(std::unordered_set<GLOBAL_CB_NODE *> *cb_bindings, VK_OBJECT obj, GLOBAL_CB_NODE *cb_node) {
33347e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_bindings->insert(cb_node);
33357e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_node->object_bindings.insert(obj);
33367e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
33377e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For a given object, if cb_node is in that objects cb_bindings, remove cb_node
33387e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void removeCommandBufferBinding(layer_data *dev_data, VK_OBJECT const *object, GLOBAL_CB_NODE *cb_node) {
33397e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_obj = GetStateStructPtrFromObject(dev_data, *object);
3340cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (base_obj) base_obj->cb_bindings.erase(cb_node);
3341bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis}
33425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Reset the command buffer state
33435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Maintain the createInfo and set state to CB_NEW, but clear all other state
3344400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlisstatic void resetCB(layer_data *dev_data, const VkCommandBuffer cb) {
3345400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis    GLOBAL_CB_NODE *pCB = dev_data->commandBufferMap[cb];
33465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
3347b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        pCB->in_use.store(0);
3348347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        pCB->last_cmd = CMD_NONE;
33495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Reset CB state (note that createInfo is not cleared)
33505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->commandBuffer = cb;
33515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
33525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
3353b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes        pCB->hasDrawCmd = false;
33545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->state = CB_NEW;
33555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->submitCount = 0;
33565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status = 0;
3357b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->viewportMask = 0;
3358b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->scissorMask = 0;
335993c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
336072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
336172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            pCB->lastBound[i].reset();
336272d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        }
336393c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
33645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo));
3365ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        pCB->activeRenderPass = nullptr;
33665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE;
33675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpass = 0;
3368e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        pCB->broken_bindings.clear();
33695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEvents.clear();
33705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.clear();
3371c7e6bc41aa9c6e5a677b138b9459b252cd3bedf2Mark Lobodzinski        pCB->writeEventsBeforeWait.clear();
33725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEventsBeforeQueryReset.clear();
33735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->queryToStateMap.clear();
33745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.clear();
33755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->startedQueries.clear();
33765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->imageLayoutMap.clear();
33775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->eventToStageMap.clear();
33785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->drawData.clear();
33795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.clear();
338058b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        pCB->vertex_buffer_used = false;
33815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->primaryCommandBuffer = VK_NULL_HANDLE;
3382bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        // Make sure any secondaryCommandBuffers are removed from globalInFlight
3383bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        for (auto secondary_cb : pCB->secondaryCommandBuffers) {
3384bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis            dev_data->globalInFlightCmdBuffers.erase(secondary_cb);
3385bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
33865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->secondaryCommandBuffers.clear();
33877a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateImages.clear();
33887a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateBuffers.clear();
3389400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, pCB);
3390b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.clear();
3391d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.clear();
339293c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
3393bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        // Remove object bindings
3394bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        for (auto obj : pCB->object_bindings) {
3395bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis            removeCommandBufferBinding(dev_data, &obj, pCB);
3396bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        }
3397a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        pCB->object_bindings.clear();
339893c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        // Remove this cmdBuffer's reference from each FrameBuffer's CB ref list
339993c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        for (auto framebuffer : pCB->framebuffers) {
34009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
3401cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(pCB);
340293c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        }
340393c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        pCB->framebuffers.clear();
34047003b38da5cc27a063af3c45080f3a35438283eeTobin Ehlis        pCB->activeFramebuffer = VK_NULL_HANDLE;
34055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Set PSO-related status bits for CB, including dynamic state set via PSO
34094c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe) {
34105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Account for any dynamic state not set via this PSO
3411ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (!pPipe->graphicsPipelineCI.pDynamicState ||
3412cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        !pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount) {  // All state is static
34134052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        pCB->status |= CBSTATUS_ALL_STATE_SET;
34145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
34155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // First consider all state on
34165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Then unset any state that's noted as dynamic in PSO
34175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Finally OR that into CB statemask
34184052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        CBStatusFlags psoDynStateMask = CBSTATUS_ALL_STATE_SET;
3419ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        for (uint32_t i = 0; i < pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
3420ca546210846c65808717f8875deae39bd227c240Tobin Ehlis            switch (pPipe->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) {
3421cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_LINE_WIDTH:
3422cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET;
3423cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3424cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BIAS:
3425cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET;
3426cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3427cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
3428cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_BLEND_CONSTANTS_SET;
3429cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3430cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
3431cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET;
3432cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3433cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
3434cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET;
3435cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3436cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
3437cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET;
3438cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3439cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
3440cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET;
3441cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3442cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
3443cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // TODO : Flag error here
3444cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
34455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
34465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
34475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= psoDynStateMask;
34485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3451623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Flags validation error if the associated call is made inside a render pass. The apiName routine should ONLY be called outside a
3452623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// render pass.
345351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool insideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3454e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool inside = false;
34555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass) {
345651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        inside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3457ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         (uint64_t)pCB->commandBuffer, __LINE__, msgCode, "DS",
3458ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         "%s: It is invalid to issue this call inside an active render pass (0x%" PRIxLEAST64 "). %s", apiName,
3459ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         (uint64_t)pCB->activeRenderPass->renderPass, validation_error_map[msgCode]);
34605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return inside;
34625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Flags validation error if the associated call is made outside a render pass. The apiName
34655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// routine should ONLY be called inside a render pass.
346651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool outsideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3467e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool outside = false;
34685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
34695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
34705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
347151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        outside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3472ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          (uint64_t)pCB->commandBuffer, __LINE__, msgCode, "DS",
3473ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          "%s: This call must be issued inside an active render pass. %s", apiName, validation_error_map[msgCode]);
34745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return outside;
34765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3478f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic void init_core_validation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
3479b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
34805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3482747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbesstatic void checkInstanceRegisterExtensions(const VkInstanceCreateInfo *pCreateInfo, instance_layer_data *instance_data) {
3483747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
3484747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SURFACE_EXTENSION_NAME))
3485747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->surfaceExtensionEnabled = true;
3486747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_EXTENSION_NAME))
3487747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->displayExtensionEnabled = true;
3488747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
3489747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_ANDROID_SURFACE_EXTENSION_NAME))
3490747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->androidSurfaceExtensionEnabled = true;
3491747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3492747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
3493747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MIR_SURFACE_EXTENSION_NAME))
3494747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->mirSurfaceExtensionEnabled = true;
3495747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3496747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
3497747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME))
3498747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->waylandSurfaceExtensionEnabled = true;
3499747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3500747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
3501747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WIN32_SURFACE_EXTENSION_NAME))
3502747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->win32SurfaceExtensionEnabled = true;
3503747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3504747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
3505747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XCB_SURFACE_EXTENSION_NAME))
3506747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->xcbSurfaceExtensionEnabled = true;
3507747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3508747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
3509747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XLIB_SURFACE_EXTENSION_NAME))
3510747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->xlibSurfaceExtensionEnabled = true;
3511747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3512747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
3513747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
3514747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
35157a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis// For the given ValidationCheck enum, set all relevant instance disabled flags to true
35167a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlisvoid SetDisabledFlags(instance_layer_data *instance_data, VkValidationFlagsEXT *val_flags_struct) {
35177a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    for (uint32_t i = 0; i < val_flags_struct->disabledValidationCheckCount; ++i) {
35187a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        switch (val_flags_struct->pDisabledValidationChecks[i]) {
35197a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            case VK_VALIDATION_CHECK_ALL_EXT:
35207a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                // Set all disabled flags to true
35217a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                instance_data->disabled.SetAll(true);
35227a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                break;
35237a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            default:
35247a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                break;
35257a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        }
35267a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    }
35277a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis}
35287a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis
3529bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
3530bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkInstance *pInstance) {
35315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
35325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
35345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
35355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
3536cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
35375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
35395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
35405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
3542cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (result != VK_SUCCESS) return result;
35435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
354456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
354556a5ba3e60a723781945959ffc10e2e215350de5Chia-I Wu    instance_data->instance = *pInstance;
35469172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
35479172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->report_data = debug_report_create_instance(
35489172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
3549747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    checkInstanceRegisterExtensions(pCreateInfo, instance_data);
3550b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    init_core_validation(instance_data, pAllocator);
3551825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski
35525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
35537a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    // Parse any pNext chains
35547a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    if (pCreateInfo->pNext) {
35557a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        GENERIC_HEADER *struct_header = (GENERIC_HEADER *)pCreateInfo->pNext;
35567a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        while (struct_header) {
35577a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            // Check for VkValidationFlagsExt
35587a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            if (VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT == struct_header->sType) {
35597a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                SetDisabledFlags(instance_data, (VkValidationFlagsEXT *)struct_header);
35607a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            }
35617a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            struct_header = (GENERIC_HEADER *)struct_header->pNext;
35627a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        }
35637a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    }
35645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
35665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
356825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Hook DestroyInstance to remove tableInstanceMap entry
356989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
35705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
35715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(instance);
35725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TBD: Need any locking this early, in case this function is called at the
35735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // same time by more than one thread?
357456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
35759172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
35765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3577b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
35785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Clean up logging callback, if any
35799172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    while (instance_data->logging_callback.size() > 0) {
35809172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
35819172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
35829172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        instance_data->logging_callback.pop_back();
35835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
35845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35859172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_debug_report_destroy_instance(instance_data->report_data);
35865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data_map.erase(key);
35875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
358915ff171550065db9f978e9d0d639629beae3038fChris Forbesstatic void checkDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, devExts *exts) {
359015ff171550065db9f978e9d0d639629beae3038fChris Forbes
359115ff171550065db9f978e9d0d639629beae3038fChris Forbes    static const std::pair<char const *, bool devExts::*> known_extensions[] {
3592599899dabe438a8ea144c0add628d3f5afe54dd0Chris Forbes        {VK_KHR_SWAPCHAIN_EXTENSION_NAME, &devExts::khr_swapchain_enabled},
3593599899dabe438a8ea144c0add628d3f5afe54dd0Chris Forbes        {VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME, &devExts::khr_display_swapchain_enabled},
359415ff171550065db9f978e9d0d639629beae3038fChris Forbes        {VK_NV_GLSL_SHADER_EXTENSION_NAME, &devExts::nv_glsl_shader_enabled},
359515ff171550065db9f978e9d0d639629beae3038fChris Forbes        {VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, &devExts::khr_descriptor_update_template_enabled},
359615ff171550065db9f978e9d0d639629beae3038fChris Forbes        {VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, &devExts::khr_shader_draw_parameters_enabled},
359715ff171550065db9f978e9d0d639629beae3038fChris Forbes        {VK_KHR_MAINTENANCE1_EXTENSION_NAME, &devExts::khr_maintenance1_enabled},
359815ff171550065db9f978e9d0d639629beae3038fChris Forbes        {VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME, &devExts::nv_geometry_shader_passthrough_enabled},
359915ff171550065db9f978e9d0d639629beae3038fChris Forbes        {VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME, &devExts::nv_sample_mask_override_coverage_enabled},
360015ff171550065db9f978e9d0d639629beae3038fChris Forbes        {VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME, &devExts::nv_viewport_array2_enabled},
360115ff171550065db9f978e9d0d639629beae3038fChris Forbes        {VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, &devExts::khr_subgroup_ballot_enabled},
360215ff171550065db9f978e9d0d639629beae3038fChris Forbes        {VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, &devExts::khr_subgroup_vote_enabled},
360315ff171550065db9f978e9d0d639629beae3038fChris Forbes    };
36045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36053f253ab4d7ecd9a232fd7ead50fe5d44ddd1cd58Chris Forbes    for (auto ext : known_extensions) {
36063f253ab4d7ecd9a232fd7ead50fe5d44ddd1cd58Chris Forbes        exts->*(ext.second) = false;
36073f253ab4d7ecd9a232fd7ead50fe5d44ddd1cd58Chris Forbes    }
36083f253ab4d7ecd9a232fd7ead50fe5d44ddd1cd58Chris Forbes
360915ff171550065db9f978e9d0d639629beae3038fChris Forbes    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
361015ff171550065db9f978e9d0d639629beae3038fChris Forbes        for (auto ext : known_extensions) {
361115ff171550065db9f978e9d0d639629beae3038fChris Forbes            if (!strcmp(ext.first, pCreateInfo->ppEnabledExtensionNames[i])) {
361215ff171550065db9f978e9d0d639629beae3038fChris Forbes                exts->*(ext.second) = true;
361315ff171550065db9f978e9d0d639629beae3038fChris Forbes                break;
361415ff171550065db9f978e9d0d639629beae3038fChris Forbes            }
3615ae17c7b673b9763c8e74bb70ed9e53b00aca8081Mark Lobodzinski        }
36165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3619838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski// Verify that queue family has been properly requested
3620ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblenstatic bool ValidateRequestedQueueFamilyProperties(instance_layer_data *instance_data, VkPhysicalDevice gpu,
3621ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                                                   const VkDeviceCreateInfo *create_info) {
36223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
36239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, gpu);
3624838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    // First check is app has actually requested queueFamilyProperties
36254b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    if (!physical_device_state) {
36263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
36273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        0, __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
36283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid call to vkCreateDevice() w/o first calling vkEnumeratePhysicalDevices().");
36294b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    } else if (QUERY_DETAILS != physical_device_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
3630838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        // TODO: This is not called out as an invalid use in the spec so make more informative recommendation.
36313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
36323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST, "DL",
36333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Call to vkCreateDevice() w/o first calling vkGetPhysicalDeviceQueueFamilyProperties().");
3634838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    } else {
3635838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        // Check that the requested queue properties are valid
3636838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) {
3637838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            uint32_t requestedIndex = create_info->pQueueCreateInfos[i].queueFamilyIndex;
36387d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes            if (requestedIndex >= physical_device_state->queue_family_properties.size()) {
36393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
36404b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes                    instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
3641838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                    __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST, "DL",
3642838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                    "Invalid queue create request in vkCreateDevice(). Invalid queueFamilyIndex %u requested.", requestedIndex);
3643838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            } else if (create_info->pQueueCreateInfos[i].queueCount >
36447d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes                       physical_device_state->queue_family_properties[requestedIndex].queueCount) {
36453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
36463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
36473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST, "DL",
36483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "Invalid queue create request in vkCreateDevice(). QueueFamilyIndex %u only has %u queues, but "
36493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "requested queueCount is %u.",
36503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                requestedIndex, physical_device_state->queue_family_properties[requestedIndex].queueCount,
36513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                create_info->pQueueCreateInfos[i].queueCount);
3652838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            }
3653838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        }
3654838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    }
36553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
3656838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski}
3657838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski
3658f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski// Verify that features have been queried and that they are available
3659bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateRequestedFeatures(instance_layer_data *dev_data, VkPhysicalDevice phys,
3660bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                      const VkPhysicalDeviceFeatures *requested_features) {
36613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3662f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
36639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto phys_device_state = GetPhysicalDeviceState(dev_data, phys);
36643bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    const VkBool32 *actual = reinterpret_cast<VkBool32 *>(&phys_device_state->features);
3665825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski    const VkBool32 *requested = reinterpret_cast<const VkBool32 *>(requested_features);
3666f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // TODO : This is a nice, compact way to loop through struct, but a bad way to report issues
3667f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  Need to provide the struct member name with the issue. To do that seems like we'll
3668f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  have to loop through each struct member which should be done w/ codegen to keep in synch.
3669f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t errors = 0;
3670f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t total_bools = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
3671f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    for (uint32_t i = 0; i < total_bools; i++) {
3672f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        if (requested[i] > actual[i]) {
3673f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            // TODO: Add index to struct member name helper to be able to include a feature name
36743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
36753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            0, __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
36763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "While calling vkCreateDevice(), requesting feature #%u in VkPhysicalDeviceFeatures struct, "
36773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "which is not available on this device.",
36783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            i);
3679f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            errors++;
3680f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        }
3681f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
36823bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    if (errors && (UNCALLED == phys_device_state->vkGetPhysicalDeviceFeaturesState)) {
3683f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // If user didn't request features, notify them that they should
3684f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // TODO: Verify this against the spec. I believe this is an invalid use of the API and should return an error
36853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
36863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
36873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "You requested features that are unavailable on this device. You should first query feature "
36883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "availability by calling vkGetPhysicalDeviceFeatures().");
3689f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
36903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
3691f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
3692f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
369389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
369489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
369556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
36963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3697f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
3698f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // Check that any requested features are available
3699f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    if (pCreateInfo->pEnabledFeatures) {
37003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateRequestedFeatures(instance_data, gpu, pCreateInfo->pEnabledFeatures);
3701f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
37023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateRequestedQueueFamilyProperties(instance_data, gpu, pCreateInfo);
3703f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
37043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
37051d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller        return VK_ERROR_VALIDATION_FAILED_EXT;
37061d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller    }
37071d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller
37085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
37095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
37115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
37125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
371356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice");
37145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (fpCreateDevice == NULL) {
37155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_INITIALIZATION_FAILED;
37165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
37195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
37205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
37225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result != VK_SUCCESS) {
37235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return result;
37245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3726b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
372756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
37285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
372956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->instance_data = instance_data;
37305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Setup device dispatch table
373156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
373256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->device = *pDevice;
3733ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    // Save PhysicalDevice handle
373456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->physical_device = gpu;
37355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
373656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->report_data = layer_debug_report_create_device(instance_data->report_data, *pDevice);
373715ff171550065db9f978e9d0d639629beae3038fChris Forbes    checkDeviceRegisterExtensions(pCreateInfo, &device_data->device_extensions);
37385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Get physical device limits for this device
373956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &(device_data->phys_dev_properties.properties));
37405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t count;
374156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
374256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->phys_dev_properties.queue_family_properties.resize(count);
374356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(
374456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        gpu, &count, &device_data->phys_dev_properties.queue_family_properties[0]);
37455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO: device limits should make sure these are compatible
37465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCreateInfo->pEnabledFeatures) {
374756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        device_data->enabled_features = *pCreateInfo->pEnabledFeatures;
37485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
374956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        memset(&device_data->enabled_features, 0, sizeof(VkPhysicalDeviceFeatures));
37505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3751e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    // Store physical device properties and physical device mem limits into device layer_data structs
375256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceMemoryProperties(gpu, &device_data->phys_dev_mem_props);
375356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &device_data->phys_dev_props);
3754b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
37555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
37575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
37595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// prototype
376289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
37635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
37643ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    bool skip = false;
37655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(device);
376656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(key, layer_data_map);
37675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Free all the memory
3768b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
37695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePipelines(dev_data);
3770fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    dev_data->renderPassMap.clear();
37719b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes    for (auto ii = dev_data->commandBufferMap.begin(); ii != dev_data->commandBufferMap.end(); ++ii) {
37729b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes        delete (*ii).second;
37739b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes    }
37749b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes    dev_data->commandBufferMap.clear();
3775f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // This will also delete all sets in the pool & remove them from setMap
37765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePools(dev_data);
3777f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // All sets should be removed
3778f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    assert(dev_data->setMap.empty());
3779a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    for (auto del_layout : dev_data->descriptorSetLayoutMap) {
3780a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis        delete del_layout.second;
3781a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    }
3782fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis    dev_data->descriptorSetLayoutMap.clear();
37835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageViewMap.clear();
37845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageMap.clear();
37855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageSubresourceMap.clear();
37865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageLayoutMap.clear();
37875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferViewMap.clear();
37885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferMap.clear();
37891344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    // Queues persist until device is destroyed
37901344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    dev_data->queueMap.clear();
37915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Report any memory leaks
37925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_debug_report_destroy_device(device);
3793b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
37945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if DISPATCH_MAP_DEBUG
3796414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller    fprintf(stderr, "Device: 0x%p, key: 0x%p\n", device, key);
37975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
37983ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    if (!skip) {
37994a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyDevice(device, pAllocator);
38003ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis        layer_data_map.erase(key);
38015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
38025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
38045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
38055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3806208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis// For given stage mask, if Geometry shader stage is on w/o GS being enabled, report geo_error_id
3807208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis//   and if Tessellation Control or Evaluation shader stages are on w/o TS being enabled, report tess_error_id
3808208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlisstatic bool ValidateStageMaskGsTsEnables(layer_data *dev_data, VkPipelineStageFlags stageMask, const char *caller,
3809208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                         UNIQUE_VALIDATION_ERROR_CODE geo_error_id, UNIQUE_VALIDATION_ERROR_CODE tess_error_id) {
3810208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    bool skip = false;
3811208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.geometryShader && (stageMask & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) {
3812208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
3813cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        geo_error_id, "DL",
3814cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT bit set when "
3815cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "device does not have geometryShader feature enabled. %s",
3816208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[geo_error_id]);
3817208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
3818208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.tessellationShader &&
3819208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        (stageMask & (VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT))) {
3820208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
3821cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        tess_error_id, "DL",
3822cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT "
3823cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "and/or VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT bit(s) set when device "
3824cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "does not have tessellationShader feature enabled. %s",
3825208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[tess_error_id]);
3826208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
3827208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    return skip;
3828208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis}
3829208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis
3830ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes// Loop through bound objects and increment their in_use counts.
3831ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayesstatic void IncrementBoundObjects(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
3832a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
3833a317e7593a0fe227635fc8241908471acb36c952Chris Forbes        auto base_obj = GetStateStructPtrFromObject(dev_data, obj);
3834ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes        if (base_obj) {
383551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            base_obj->in_use.fetch_add(1);
3836162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis        }
3837a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
3838a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
38395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Track which resources are in-flight by atomically incrementing their "in_use" count
384051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void incrementResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
384151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    cb_node->submitCount++;
38429a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    cb_node->in_use.fetch_add(1);
38439a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    dev_data->globalInFlightCmdBuffers.insert(cb_node->commandBuffer);
3844a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
3845a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // First Increment for all "generic" objects bound to cmd buffer, followed by special-case objects below
3846ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes    IncrementBoundObjects(dev_data, cb_node);
3847a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
3848a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
3849a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  should then be flagged prior to calling this function
38509a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto drawDataElement : cb_node->drawData) {
38515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto buffer : drawDataElement.buffers) {
38529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto buffer_state = GetBufferState(dev_data, buffer);
385351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (buffer_state) {
38545cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                buffer_state->in_use.fetch_add(1);
38555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
38565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
38575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
38589a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto event : cb_node->writeEventsBeforeWait) {
38599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
3860cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (event_state) event_state->write_in_use++;
3861c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
38625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3864b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Note: This function assumes that the global lock is held by the calling thread.
3865b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// For the given queue, verify the queue state up to the given seq number.
3866b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Currently the only check is to make sure that if there are events to be waited on prior to
3867b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis//  a QueryReset, make sure that all such events have been signalled.
3868d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbesstatic bool VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *initial_queue, uint64_t initial_seq) {
3869b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    bool skip = false;
3870d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3871d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    // sequence number we want to validate up to, per queue
3872d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::unordered_map<QUEUE_STATE *, uint64_t> target_seqs { { initial_queue, initial_seq } };
3873d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    // sequence number we've completed validation for, per queue
3874d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::unordered_map<QUEUE_STATE *, uint64_t> done_seqs;
3875d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::vector<QUEUE_STATE *> worklist { initial_queue };
3876d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3877d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    while (worklist.size()) {
3878d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto queue = worklist.back();
3879d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        worklist.pop_back();
3880d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3881d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto target_seq = target_seqs[queue];
3882d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto seq = std::max(done_seqs[queue], queue->seq);
3883d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto sub_it = queue->submissions.begin() + int(seq - queue->seq);  // seq >= queue->seq
3884d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3885d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        for (; seq < target_seq; ++sub_it, ++seq) {
3886d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            for (auto &wait : sub_it->waitSemaphores) {
3887d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_queue = GetQueueState(dev_data, wait.queue);
3888d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3889d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (other_queue == queue)
3890d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    continue;   // semaphores /always/ point backwards, so no point here.
3891d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3892d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_target_seq = std::max(target_seqs[other_queue], wait.seq);
3893d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_done_seq = std::max(done_seqs[other_queue], other_queue->seq);
3894d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3895d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // if this wait is for another queue, and covers new sequence
3896d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // numbers beyond what we've already validated, mark the new
3897d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // target seq and (possibly-re)add the queue to the worklist.
3898d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (other_done_seq < other_target_seq) {
3899d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    target_seqs[other_queue] = other_target_seq;
3900d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    worklist.push_back(other_queue);
3901d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                }
3902d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            }
3903d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3904d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            for (auto cb : sub_it->cbs) {
3905d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto cb_node = GetCBNode(dev_data, cb);
3906d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (cb_node) {
3907d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    for (auto queryEventsPair : cb_node->waitedEventsBeforeQueryReset) {
3908d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                        for (auto event : queryEventsPair.second) {
3909d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                            if (dev_data->eventMap[event].needsSignaled) {
3910d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3911d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS",
3912d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                "Cannot get query results on queryPool 0x%" PRIx64
3913d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                " with index %d which was guarded by unsignaled event 0x%" PRIx64 ".",
3914d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event));
3915d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                            }
3916b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                        }
3917b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    }
3918b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine                }
3919b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine            }
3920b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        }
3921d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3922d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        // finally mark the point we've now validated this queue to.
3923d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        done_seqs[queue] = seq;
392492b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    }
3925d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3926b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return skip;
3927b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis}
3928b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis
3929b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// When the given fence is retired, verify outstanding queue operations through the point of the fence
3930b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic bool VerifyQueueStateToFence(layer_data *dev_data, VkFence fence) {
39319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto fence_state = GetFenceNode(dev_data, fence);
3932b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    if (VK_NULL_HANDLE != fence_state->signaler.first) {
39339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        return VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, fence_state->signaler.first), fence_state->signaler.second);
3934b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    }
3935b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return false;
3936b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
39377d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes
39387d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes// TODO: nuke this completely.
3939b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine// Decrement cmd_buffer in_use and if it goes to 0 remove cmd_buffer from globalInFlightCmdBuffers
3940b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentinestatic inline void removeInFlightCmdBuffer(layer_data *dev_data, VkCommandBuffer cmd_buffer) {
3941b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    // Pull it off of global list initially, but if we find it in any other queue list, add it back in
39429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, cmd_buffer);
3943b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    pCB->in_use.fetch_sub(1);
3944b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    if (!pCB->in_use.load()) {
3945b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
3946b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    }
3947b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
3948b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
3949a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis// Decrement in-use count for objects bound to command buffer
39502f8cbf3b166e175174877a59929902e005953d6dTobin Ehlisstatic void DecrementBoundResources(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
395100e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis    BASE_NODE *base_obj = nullptr;
3952a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
39537e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis        base_obj = GetStateStructPtrFromObject(dev_data, obj);
395400e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        if (base_obj) {
395500e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis            base_obj->in_use.fetch_sub(1);
395600e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        }
3957a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
3958a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
3959da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes
396036c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void RetireWorkOnQueue(layer_data *dev_data, QUEUE_STATE *pQueue, uint64_t seq) {
39619867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unordered_map<VkQueue, uint64_t> otherQueueSeqs;
39629867daedbf52debc77d6568162ee21e071699b80Chris Forbes
39639867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll this queue forward, one submission at a time.
39649867daedbf52debc77d6568162ee21e071699b80Chris Forbes    while (pQueue->seq < seq) {
3965bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &submission = pQueue->submissions.front();
39669867daedbf52debc77d6568162ee21e071699b80Chris Forbes
3967bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &wait : submission.waitSemaphores) {
39689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, wait.semaphore);
3969c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
3970c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
3971c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
3972bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto &lastSeq = otherQueueSeqs[wait.queue];
39739867daedbf52debc77d6568162ee21e071699b80Chris Forbes            lastSeq = std::max(lastSeq, wait.seq);
3974da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes        }
3975cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
3976bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &semaphore : submission.signalSemaphores) {
39779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
3978c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
3979c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
3980c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
39819867daedbf52debc77d6568162ee21e071699b80Chris Forbes        }
3982cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
39839867daedbf52debc77d6568162ee21e071699b80Chris Forbes        for (auto cb : submission.cbs) {
39849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, cb);
3985c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (!cb_node) {
3986c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                continue;
3987c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
3988a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis            // First perform decrement on general case bound objects
39899a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            DecrementBoundResources(dev_data, cb_node);
39909a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto drawDataElement : cb_node->drawData) {
39919867daedbf52debc77d6568162ee21e071699b80Chris Forbes                for (auto buffer : drawDataElement.buffers) {
39929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto buffer_state = GetBufferState(dev_data, buffer);
39935cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                    if (buffer_state) {
39945cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                        buffer_state->in_use.fetch_sub(1);
39959867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
39969867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
3997da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
39989a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto event : cb_node->writeEventsBeforeWait) {
39999867daedbf52debc77d6568162ee21e071699b80Chris Forbes                auto eventNode = dev_data->eventMap.find(event);
40009867daedbf52debc77d6568162ee21e071699b80Chris Forbes                if (eventNode != dev_data->eventMap.end()) {
40019867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    eventNode->second.write_in_use--;
40029867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
40039867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
40049a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto queryStatePair : cb_node->queryToStateMap) {
40059867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->queryToStateMap[queryStatePair.first] = queryStatePair.second;
40069867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
40079a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto eventStagePair : cb_node->eventToStageMap) {
40089867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second;
4009da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
40100a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine
40119867daedbf52debc77d6568162ee21e071699b80Chris Forbes            removeInFlightCmdBuffer(dev_data, cb);
40120a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
40139867daedbf52debc77d6568162ee21e071699b80Chris Forbes
40149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, submission.fence);
40159867daedbf52debc77d6568162ee21e071699b80Chris Forbes        if (pFence) {
40169867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pFence->state = FENCE_RETIRED;
40170a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
40189867daedbf52debc77d6568162ee21e071699b80Chris Forbes
40199867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->submissions.pop_front();
40209867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->seq++;
4021b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
40229867daedbf52debc77d6568162ee21e071699b80Chris Forbes
40239867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll other queues forward to the highest seq we saw a wait for
40249867daedbf52debc77d6568162ee21e071699b80Chris Forbes    for (auto qs : otherQueueSeqs) {
40259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, qs.first), qs.second);
4026d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
40279867daedbf52debc77d6568162ee21e071699b80Chris Forbes}
4028651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
4029651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// Submit a fence to a queue, delimiting previous fences and previous untracked
4030651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// work by it.
403136c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void SubmitFence(QUEUE_STATE *pQueue, FENCE_NODE *pFence, uint64_t submitCount) {
4032cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes    pFence->state = FENCE_INFLIGHT;
40339867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.first = pQueue->queue;
40349867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.second = pQueue->seq + pQueue->submissions.size() + submitCount;
4035b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
4036b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
403751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
40383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
403951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if ((dev_data->globalInFlightCmdBuffers.count(pCB->commandBuffer) || current_submit_count > 1) &&
40405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
40413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
40423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        __LINE__, VALIDATION_ERROR_00133, "DS",
40433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Command Buffer 0x%p is already in use and is not marked for simultaneous use. %s", pCB->commandBuffer,
40443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_00133]);
40455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
40463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
40475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4049946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskistatic bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source,
4050440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                                       int current_submit_count) {
4051c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    bool skip = false;
4052cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.command_buffer_state) return skip;
40530a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
4054946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if ((cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) &&
4055946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        (cb_state->submitCount + current_submit_count > 1)) {
4056c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4057c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
4058226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Commandbuffer 0x%p was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT "
4059c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        "set, but has been submitted 0x%" PRIxLEAST64 " times.",
4060946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->commandBuffer, cb_state->submitCount + current_submit_count);
40610a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    }
40625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate that cmd buffers have been updated
4063946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (CB_RECORDED != cb_state->state) {
4064946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (CB_INVALID == cb_state->state) {
4065946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= ReportInvalidCommandBuffer(dev_data, cb_state, call_source);
4066cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Flag error for using CB w/o vkEndCommandBuffer() called
4067c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4068946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS",
4069946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "You must call vkEndCommandBuffer() on command buffer 0x%p before this call to %s!",
4070946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            cb_state->commandBuffer, call_source);
40715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
40725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4073c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    return skip;
40745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
407651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
40773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
407851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
407951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
408051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
408151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  should then be flagged prior to calling this function
408251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (auto drawDataElement : cb_node->drawData) {
408351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (auto buffer : drawDataElement.buffers) {
408451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto buffer_state = GetBufferState(dev_data, buffer);
408551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (!buffer_state) {
40863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
40873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                (uint64_t)(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
40883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "Cannot submit cmd buffer using deleted buffer 0x%" PRIx64 ".", (uint64_t)(buffer));
408951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
409051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
409151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
40923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
409351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
409451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
4095f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski// Check that the queue family index of 'queue' matches one of the entries in pQueueFamilyIndices
4096f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinskibool ValidImageBufferQueue(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const VK_OBJECT *object, VkQueue queue, uint32_t count,
4097f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           const uint32_t *indices) {
4098f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    bool found = false;
4099f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    bool skip = false;
4100f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    auto queue_state = GetQueueState(dev_data, queue);
4101f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    if (queue_state) {
4102f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        for (uint32_t i = 0; i < count; i++) {
4103f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            if (indices[i] == queue_state->queueFamilyIndex) {
4104f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                found = true;
4105f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                break;
4106f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            }
4107f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
4108f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
4109f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        if (!found) {
411002a510945ff39f3d9e486e456aca5bfa6ea0c43aMark Lobodzinski            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object->type],
411102a510945ff39f3d9e486e456aca5bfa6ea0c43aMark Lobodzinski                           object->handle, __LINE__, DRAWSTATE_INVALID_QUEUE_FAMILY, "DS",
4112f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           "vkQueueSubmit: Command buffer 0x%" PRIxLEAST64 " contains %s 0x%" PRIxLEAST64
4113f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           " which was not created allowing concurrent access to this queue family %d.",
41147a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                           reinterpret_cast<uint64_t>(cb_node->commandBuffer), object_string[object->type], object->handle,
4115f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           queue_state->queueFamilyIndex);
4116f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
4117f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    }
4118f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    return skip;
4119f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski}
4120f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
41217bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Validate that queueFamilyIndices of primary command buffers match this queue
41227bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Secondary command buffers were previously validated in vkCmdExecuteCommands().
41237bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinskistatic bool validateQueueFamilyIndices(layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkQueue queue) {
41243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
41259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
41269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
41277bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
4128f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    if (pPool && queue_state) {
4129f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        if (pPool->queueFamilyIndex != queue_state->queueFamilyIndex) {
41303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
41313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_00139, "DS",
41323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkQueueSubmit: Primary command buffer 0x%p created in queue family %d is being submitted on queue "
41333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "0x%p from queue family %d. %s",
41343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            pCB->commandBuffer, pPool->queueFamilyIndex, queue, queue_state->queueFamilyIndex,
41353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_00139]);
4136f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
4137f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
4138f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        // Ensure that any bound images or buffers created with SHARING_MODE_CONCURRENT have access to the current queue family
4139f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        for (auto object : pCB->object_bindings) {
41407a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            if (object.type == kVulkanObjectTypeImage) {
4141f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(object.handle));
4142f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                if (image_state && image_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
41433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= ValidImageBufferQueue(dev_data, pCB, &object, queue, image_state->createInfo.queueFamilyIndexCount,
41443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                  image_state->createInfo.pQueueFamilyIndices);
4145f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                }
41467a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            } else if (object.type == kVulkanObjectTypeBuffer) {
4147f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object.handle));
4148f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                if (buffer_state && buffer_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
41493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= ValidImageBufferQueue(dev_data, pCB, &object, queue, buffer_state->createInfo.queueFamilyIndexCount,
41503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                  buffer_state->createInfo.pQueueFamilyIndices);
4151f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                }
4152f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            }
4153f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
41547bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
41557bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
41563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
41577bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski}
41587bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
415951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
41605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Track in-use for resources off of primary and any secondary CBs
41613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
4162a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4163a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
4164a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // on device
41653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateCommandBufferSimultaneousUse(dev_data, pCB, current_submit_count);
4166a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
41673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateResources(dev_data, pCB);
4168a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
41695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pCB->secondaryCommandBuffers.empty()) {
41705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) {
41719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            GLOBAL_CB_NODE *pSubCB = GetCBNode(dev_data, secondaryCmdBuffer);
41723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateResources(dev_data, pSubCB);
41734c665b29a9d2906a378417546c7fc6436731d07fTobin Ehlis            if ((pSubCB->primaryCommandBuffer != pCB->commandBuffer) &&
41744c665b29a9d2906a378417546c7fc6436731d07fTobin Ehlis                !(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4175f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                log_msg(
4176f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4177f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    __LINE__, VALIDATION_ERROR_00135, "DS",
4178f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "Commandbuffer 0x%p was submitted with secondary buffer 0x%p but that buffer has subsequently been bound to "
4179f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "primary cmd buffer 0x%p and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set. %s",
4180f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    pCB->commandBuffer, secondaryCmdBuffer, pSubCB->primaryCommandBuffer,
4181f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    validation_error_map[VALIDATION_ERROR_00135]);
41825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
41835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
41845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4185a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
41863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateCommandBufferState(dev_data, pCB, "vkQueueSubmit()", current_submit_count);
4187a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
41883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
41895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
41905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4191bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateFenceForSubmit(layer_data *dev_data, FENCE_NODE *pFence) {
41923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
419381c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4194651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
4195cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_INFLIGHT) {
4196f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            // TODO: opportunities for VALIDATION_ERROR_00127, VALIDATION_ERROR_01647, VALIDATION_ERROR_01953
41973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
41983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            (uint64_t)(pFence->fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
41993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Fence 0x%" PRIx64 " is already in use by another submission.", (uint64_t)(pFence->fence));
4200a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
420181c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4202cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        else if (pFence->state == FENCE_RETIRED) {
4203f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            // TODO: opportunities for VALIDATION_ERROR_00126, VALIDATION_ERROR_01646, VALIDATION_ERROR_01953
42043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
42053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(pFence->fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
42063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Fence 0x%" PRIxLEAST64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
42073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(pFence->fence));
4208a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
42095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
421081c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
42113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
421281c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes}
421381c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
421451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void PostCallRecordQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
421551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                      VkFence fence) {
42169a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
42179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4218d7d60cccc862fee2d0b3ad410c5fdcc40ddc83aeChris Forbes
4219651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    // Mark the fence in-use.
4220651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
42219867daedbf52debc77d6568162ee21e071699b80Chris Forbes        SubmitFence(pQueue, pFence, std::max(1u, submitCount));
4222651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    }
4223651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
422451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now process each individual submit
42255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
422651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        std::vector<VkCommandBuffer> cbs;
42275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubmitInfo *submit = &pSubmits[submit_idx];
42289867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<SEMAPHORE_WAIT> semaphore_waits;
42299867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<VkSemaphore> semaphore_signals;
42305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
423151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pWaitSemaphores[i];
423251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
423351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
423451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
423551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
423651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    pSemaphore->in_use.fetch_add(1);
423751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
423851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = VK_NULL_HANDLE;
423951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = false;
424051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
424151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
424251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
424351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pSignalSemaphores[i];
424451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
424551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
424651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = queue;
424751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
424851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = true;
424951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->in_use.fetch_add(1);
425051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                semaphore_signals.push_back(semaphore);
425151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
425251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
425351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
425451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
425551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (cb_node) {
425651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                cbs.push_back(submit->pCommandBuffers[i]);
425751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                for (auto secondaryCmdBuffer : cb_node->secondaryCommandBuffers) {
425851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    cbs.push_back(secondaryCmdBuffer);
425951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
426051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                UpdateCmdBufImageLayouts(dev_data, cb_node);
426151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                incrementResources(dev_data, cb_node);
426251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (!cb_node->secondaryCommandBuffers.empty()) {
426351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    for (auto secondaryCmdBuffer : cb_node->secondaryCommandBuffers) {
426451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                        GLOBAL_CB_NODE *pSubCB = GetCBNode(dev_data, secondaryCmdBuffer);
426551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                        incrementResources(dev_data, pSubCB);
426651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    }
426751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
426851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
426951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
427051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(cbs, semaphore_waits, semaphore_signals,
427151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         submit_idx == submitCount - 1 ? fence : VK_NULL_HANDLE);
427251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
427351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
427451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if (pFence && !submitCount) {
427551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // If no submissions, but just dropping a fence on the end of the queue,
427651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // record an empty submission with just the fence, so we can determine
427751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // its completion.
427851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
427951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         fence);
428051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
428151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
428251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
428351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool PreCallValidateQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
428451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                       VkFence fence) {
428551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    auto pFence = GetFenceNode(dev_data, fence);
42863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = ValidateFenceForSubmit(dev_data, pFence);
42873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
428851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        return true;
428951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
429051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
429151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> signaled_semaphores;
429251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> unsignaled_semaphores;
429351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    vector<VkCommandBuffer> current_cmds;
429451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> localImageLayoutMap = dev_data->imageLayoutMap;
429551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now verify each individual submit
429651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
429751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        const VkSubmitInfo *submit = &pSubmits[submit_idx];
429851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
42993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateStageMaskGsTsEnables(dev_data, submit->pWaitDstStageMask[i], "vkQueueSubmit()", VALIDATION_ERROR_00142,
43003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                 VALIDATION_ERROR_00143);
430101a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pWaitSemaphores[i];
43029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
430301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
430451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (unsignaled_semaphores.count(semaphore) ||
4305440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                    (!(signaled_semaphores.count(semaphore)) && !(pSemaphore->signaled))) {
43063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
43073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
43083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
43093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    reinterpret_cast<const uint64_t &>(semaphore));
431051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                } else {
431151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.erase(semaphore);
431251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.insert(semaphore);
43131344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
43145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
43155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
43165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
431701a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pSignalSemaphores[i];
43189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
431901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
4320440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                if (signaled_semaphores.count(semaphore) || (!(unsignaled_semaphores.count(semaphore)) && pSemaphore->signaled)) {
43213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
43223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
43233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Queue 0x%p is signaling semaphore 0x%" PRIx64
43243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " that has already been signaled but not waited on by queue 0x%" PRIx64 ".",
43253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    queue, reinterpret_cast<const uint64_t &>(semaphore),
43263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    reinterpret_cast<uint64_t &>(pSemaphore->signaler.first));
43271344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
432851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.erase(semaphore);
432951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.insert(semaphore);
43301344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
43310a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine            }
43325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
43335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
43349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
4335d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            if (cb_node) {
43363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateCmdBufImageLayouts(dev_data, cb_node, localImageLayoutMap);
433751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                current_cmds.push_back(submit->pCommandBuffers[i]);
43383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= validatePrimaryCommandBufferState(
433951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    dev_data, cb_node, (int)std::count(current_cmds.begin(), current_cmds.end(), submit->pCommandBuffers[i]));
43403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= validateQueueFamilyIndices(dev_data, cb_node, queue);
434151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
4342ea371fa7c8c57edb4d1436e4570cf54f3fc0463fTobin Ehlis                // Potential early exit here as bad object state may crash in delayed function calls
43433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                if (skip) {
434451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    return true;
434551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
434651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
43471344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                // Call submit-time functions to validate/update state
4348d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->validate_functions) {
43493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function();
43501344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4351d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->eventUpdates) {
43523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function(queue);
43531344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4354d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->queryUpdates) {
43553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function(queue);
4356d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
43571344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            }
43585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
43599867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
43603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
436151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
43629867daedbf52debc77d6568162ee21e071699b80Chris Forbes
436351920949f887ce8d3666c73c28ff19a5d8325a37Tony BarbourVKAPI_ATTR VkResult VKAPI_CALL QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
436451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
436551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    std::unique_lock<std::mutex> lock(global_lock);
436651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
436751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip = PreCallValidateQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
4368b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
43695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4370440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
437151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
437251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    VkResult result = dev_data->dispatch_table.QueueSubmit(queue, submitCount, pSubmits, fence);
437351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
437451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.lock();
437551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    PostCallRecordQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
437651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.unlock();
43775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
43785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4380f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic bool PreCallValidateAllocateMemory(layer_data *dev_data) {
4381f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = false;
4382f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (dev_data->memObjMap.size() >= dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount) {
4383f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
4384f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        reinterpret_cast<const uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_00611, "MEM",
4385f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        "Number of currently valid memory objects is not less than the maximum allowed (%u). %s",
4386f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount,
4387f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        validation_error_map[VALIDATION_ERROR_00611]);
4388f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    }
4389f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return skip;
4390f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4391f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
4392f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic void PostCallRecordAllocateMemory(layer_data *dev_data, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory) {
4393f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    add_mem_obj_info(dev_data, dev_data->device, *pMemory, pAllocateInfo);
4394f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return;
4395f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4396f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
439789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
439889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
4399f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
440056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4401f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    std::unique_lock<std::mutex> lock(global_lock);
4402f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = PreCallValidateAllocateMemory(dev_data);
4403f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (!skip) {
4404f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.unlock();
4405f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        result = dev_data->dispatch_table.AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
4406f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.lock();
4407f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        if (VK_SUCCESS == result) {
4408f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz            PostCallRecordAllocateMemory(dev_data, pAllocateInfo, pMemory);
4409f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        }
4410e12739a56d02ca2fb5f0273862668e7475a21a6cMark Lobodzinski    }
44115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
44125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
44135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4414177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis// For given obj node, if it is use, flag a validation error and return callback result, else return false
4415177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisbool ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct,
4416177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                            UNIQUE_VALIDATION_ERROR_CODE error_code) {
4417cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.object_in_use) return false;
4418177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4419177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (obj_node->in_use.load()) {
44207a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip |=
442102a510945ff39f3d9e486e456aca5bfa6ea0c43aMark Lobodzinski            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[obj_struct.type], obj_struct.handle,
44227a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                    __LINE__, error_code, "DS", "Cannot delete %s 0x%" PRIx64 " that is currently in use by a command buffer. %s",
44237a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                    object_string[obj_struct.type], obj_struct.handle, validation_error_map[error_code]);
4424177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4425177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4426177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
44275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4428177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic bool PreCallValidateFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO **mem_info, VK_OBJECT *obj_struct) {
44299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *mem_info = GetMemObjInfo(dev_data, mem);
44307a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski    *obj_struct = {reinterpret_cast<uint64_t &>(mem), kVulkanObjectTypeDeviceMemory};
4431cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_memory) return false;
4432177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4433177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (*mem_info) {
4434177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *mem_info, *obj_struct, VALIDATION_ERROR_00620);
4435177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4436177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4437177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
44385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4439177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic void PostCallRecordFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO *mem_info, VK_OBJECT obj_struct) {
4440177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Clear mem binding for any bound objects
444147705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis    for (auto obj : mem_info->obj_bindings) {
444202a510945ff39f3d9e486e456aca5bfa6ea0c43aMark Lobodzinski        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, get_debug_report_enum[obj.type], obj.handle, __LINE__,
44437a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                MEMTRACK_FREED_MEM_REF, "MEM", "VK Object 0x%" PRIxLEAST64 " still has a reference to mem obj 0x%" PRIxLEAST64,
44447a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                obj.handle, (uint64_t)mem_info->mem);
444547705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        switch (obj.type) {
44467a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            case kVulkanObjectTypeImage: {
44479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
4448cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(image_state);  // Any destroyed images should already be removed from bindings
4449cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                image_state->binding.mem = MEMORY_UNBOUND;
4450cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
44527a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            case kVulkanObjectTypeBuffer: {
44539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
4454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(buffer_state);  // Any destroyed buffers should already be removed from bindings
4455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                buffer_state->binding.mem = MEMORY_UNBOUND;
4456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
4459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Should only have buffer or image objects bound to memory
4460cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(0);
4461177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        }
4462177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4463177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Any bound cmd buffers are now invalid
446439c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, mem_info->cb_bindings, obj_struct);
4465177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    dev_data->memObjMap.erase(mem);
4466177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
4467177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis
4468177063aac84fac6f4e650c2629a08b48be643f96Tobin EhlisVKAPI_ATTR void VKAPI_CALL FreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
446956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4470177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    DEVICE_MEM_INFO *mem_info = nullptr;
4471177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    VK_OBJECT obj_struct;
4472b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4473177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = PreCallValidateFreeMemory(dev_data, mem, &mem_info, &obj_struct);
4474177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (!skip) {
4475177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.unlock();
4476177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        dev_data->dispatch_table.FreeMemory(device, mem, pAllocator);
4477177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.lock();
4478405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (mem != VK_NULL_HANDLE) {
4479405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordFreeMemory(dev_data, mem, mem_info, obj_struct);
4480405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
448174243a735fe102b370237ddf80d3e6f7ec5246dbMark Mueller    }
44825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
44835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4484f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis// Validate that given Map memory range is valid. This means that the memory should not already be mapped,
4485f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  and that the size of the map range should be:
4486f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  1. Not zero
4487f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  2. Within the size of the memory allocation
448851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateMapMemRange(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
44893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
44905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (size == 0) {
44923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
44933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
44943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "VkMapMemory: Attempting to map memory range of size zero");
44955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
44965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
449751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto mem_element = dev_data->memObjMap.find(mem);
449851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (mem_element != dev_data->memObjMap.end()) {
449957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        auto mem_info = mem_element->second.get();
45005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // It is an application error to call VkMapMemory on an object that is already mapped
4501de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (mem_info->mem_range.size != 0) {
45023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
45033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
45043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           "VkMapMemory: Attempting to map memory on an already-mapped object 0x%" PRIxLEAST64, (uint64_t)mem);
45055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
45075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate that offset + size is within object's allocationSize
45085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (size == VK_WHOLE_SIZE) {
4509de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if (offset >= mem_info->alloc_info.allocationSize) {
45103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
45113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
45123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64
45133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               " with size of VK_WHOLE_SIZE oversteps total array size 0x%" PRIx64,
45143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               offset, mem_info->alloc_info.allocationSize, mem_info->alloc_info.allocationSize);
45155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
45165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
4517de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if ((offset + size) > mem_info->alloc_info.allocationSize) {
45183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
45193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               (uint64_t)mem, __LINE__, VALIDATION_ERROR_00628, "MEM",
45203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64 " oversteps total array size 0x%" PRIx64 ". %s",
45213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               offset, size + offset, mem_info->alloc_info.allocationSize,
45223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               validation_error_map[VALIDATION_ERROR_00628]);
45235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
45245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
45263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
45275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
452951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void storeMemRanges(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
45309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
453157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4532de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.offset = offset;
4533de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = size;
45345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
45355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
453751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool deleteMemRanges(layer_data *dev_data, VkDeviceMemory mem) {
45383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
45399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
454057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4541de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (!mem_info->mem_range.size) {
45425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Valid Usage: memory must currently be mapped
45433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
45443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           (uint64_t)mem, __LINE__, VALIDATION_ERROR_00649, "MEM",
45453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           "Unmapping Memory without memory being mapped: mem obj 0x%" PRIxLEAST64 ". %s", (uint64_t)mem,
45463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           validation_error_map[VALIDATION_ERROR_00649]);
45475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4548de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = 0;
45495f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info->shadow_copy) {
45505f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            free(mem_info->shadow_copy_base);
45515f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy_base = 0;
45525f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
45535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
45553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
45565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
45585f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski// Guard value for pad data
45595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char NoncoherentMemoryFillValue = 0xb;
45605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
45615f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinskistatic void initializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
45625f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                     void **ppData) {
45639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
456457fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4565de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->p_driver_data = *ppData;
4566de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        uint32_t index = mem_info->alloc_info.memoryTypeIndex;
4567b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis        if (dev_data->phys_dev_mem_props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
45685f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
45695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
45705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (size == VK_WHOLE_SIZE) {
45715f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                size = mem_info->alloc_info.allocationSize - offset;
45725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
45735f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_pad_size = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
457416769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton            assert(SafeModulo(mem_info->shadow_pad_size,
45755f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment) == 0);
45765f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Ensure start of mapped region reflects hardware alignment constraints
45775f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t map_alignment = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
45785f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
45795f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // From spec: (ppData - offset) must be aligned to at least limits::minMemoryMapAlignment.
45805f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t start_offset = offset % map_alignment;
45815f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Data passed to driver will be wrapped by a guardband of data to detect over- or under-writes.
4582bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            mem_info->shadow_copy_base =
4583bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                malloc(static_cast<size_t>(2 * mem_info->shadow_pad_size + size + map_alignment + start_offset));
45845f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
45855f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy =
45865f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(mem_info->shadow_copy_base) + map_alignment) &
4587bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         ~(map_alignment - 1)) +
4588bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                start_offset;
458916769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton            assert(SafeModulo(reinterpret_cast<uintptr_t>(mem_info->shadow_copy) + mem_info->shadow_pad_size - start_offset,
45905f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  map_alignment) == 0);
45915f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
45926e17c244b21ce43ac57404a00a0d844039eed363Mark Lobodzinski            memset(mem_info->shadow_copy, NoncoherentMemoryFillValue, static_cast<size_t>(2 * mem_info->shadow_pad_size + size));
45935f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            *ppData = static_cast<char *>(mem_info->shadow_copy) + mem_info->shadow_pad_size;
45945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
45965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45975f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
4598a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis// Verify that state for fence being waited on is appropriate. That is,
45999867daedbf52debc77d6568162ee21e071699b80Chris Forbes//  a fence being waited on should not already be signaled and
4600a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis//  it should have been submitted on a queue or during acquire next image
460149f6132af865afd5b7f413c91125971ac97c135aChris Forbesstatic inline bool verifyWaitFenceState(layer_data *dev_data, VkFence fence, const char *apiCall) {
46023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
46039b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes
46049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
46059b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes    if (pFence) {
4606cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_UNSIGNALED) {
46073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
46083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
46093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s called for fence 0x%" PRIxLEAST64
46103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " which has not been submitted on a Queue or during "
46113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "acquire next image.",
46123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            apiCall, reinterpret_cast<uint64_t &>(fence));
46135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
46145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
46153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
46165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4617a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
4618b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void RetireFence(layer_data *dev_data, VkFence fence) {
46199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4620b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes    if (pFence->signaler.first != VK_NULL_HANDLE) {
462125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is a queue -- use this as proof that prior operations on that queue have completed.
46229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, pFence->signaler.first), pFence->signaler.second);
4623bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    } else {
462425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is the WSI. We're not tracking what the WSI op actually /was/ in CV yet, but we need to mark
462525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // the fence as retired.
4626d4513979120463171eb479cdded9336eb9944da1Chris Forbes        pFence->state = FENCE_RETIRED;
4627d4513979120463171eb479cdded9336eb9944da1Chris Forbes    }
4628b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes}
4629b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes
4630accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlisstatic bool PreCallValidateWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences) {
4631cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.wait_for_fences) return false;
4632accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = false;
4633accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    for (uint32_t i = 0; i < fence_count; i++) {
4634accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        skip |= verifyWaitFenceState(dev_data, fences[i], "vkWaitForFences");
4635b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        skip |= VerifyQueueStateToFence(dev_data, fences[i]);
4636accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4637accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    return skip;
4638accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4639accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4640b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences, VkBool32 wait_all) {
4641b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    // When we know that all fences are complete we can clean/remove their CBs
4642accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    if ((VK_TRUE == wait_all) || (1 == fence_count)) {
4643accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        for (uint32_t i = 0; i < fence_count; i++) {
4644b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            RetireFence(dev_data, fences[i]);
4645accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        }
4646accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4647accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    // NOTE : Alternate case not handled here is when some fences have completed. In
4648accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    //  this case for app to guarantee which fences completed it will have to call
4649b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    //  vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
4650accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4651accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4652bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
4653bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint64_t timeout) {
465456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
46555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Verify fence status of submitted fences
4656b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4657accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = PreCallValidateWaitForFences(dev_data, fenceCount, pFences);
4658b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4659cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4660a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
46614a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.WaitForFences(device, fenceCount, pFences, waitAll, timeout);
4662414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller
46635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4664b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
4665b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordWaitForFences(dev_data, fenceCount, pFences, waitAll);
4666b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
46675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
46685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
46695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4671f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlisstatic bool PreCallValidateGetFenceStatus(layer_data *dev_data, VkFence fence) {
4672cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_fence_state) return false;
4673f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    return verifyWaitFenceState(dev_data, fence, "vkGetFenceStatus");
4674f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis}
4675f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
4676b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordGetFenceStatus(layer_data *dev_data, VkFence fence) { RetireFence(dev_data, fence); }
4677f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
467889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL GetFenceStatus(VkDevice device, VkFence fence) {
467956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4680b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4681f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    bool skip = PreCallValidateGetFenceStatus(dev_data, fence);
4682b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4683cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4684a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
46854a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetFenceStatus(device, fence);
46865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4687f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.lock();
4688b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordGetFenceStatus(dev_data, fence);
4689f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.unlock();
46905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
46915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
46925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
46943b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlisstatic void PostCallRecordGetDeviceQueue(layer_data *dev_data, uint32_t q_family_index, VkQueue queue) {
46953b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    // Add queue to tracking set only if it is new
46963b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    auto result = dev_data->queues.emplace(queue);
46973b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    if (result.second == true) {
469836c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        QUEUE_STATE *queue_state = &dev_data->queueMap[queue];
46993b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queue = queue;
47003b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queueFamilyIndex = q_family_index;
47013b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->seq = 0;
47023b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    }
47033b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis}
47043b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis
4705bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
470656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
47074a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
4708b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
4709b376edacad6f7ab3fcc0a914e9b1673a9fcd5143Mark Lobodzinski
47103b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    PostCallRecordGetDeviceQueue(dev_data, queueFamilyIndex, *pQueue);
47115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
471336c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool PreCallValidateQueueWaitIdle(layer_data *dev_data, VkQueue queue, QUEUE_STATE **queue_state) {
47149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *queue_state = GetQueueState(dev_data, queue);
4715cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.queue_wait_idle) return false;
4716e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    return VerifyQueueStateToSeq(dev_data, *queue_state, (*queue_state)->seq + (*queue_state)->submissions.size());
47174273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
47184273a1c157585a645dca4c960086032793899d05Tobin Ehlis
471936c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void PostCallRecordQueueWaitIdle(layer_data *dev_data, QUEUE_STATE *queue_state) {
4720e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    RetireWorkOnQueue(dev_data, queue_state, queue_state->seq + queue_state->submissions.size());
47214273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
47224273a1c157585a645dca4c960086032793899d05Tobin Ehlis
472389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueueWaitIdle(VkQueue queue) {
472456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
472536c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    QUEUE_STATE *queue_state = nullptr;
47269867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
47274273a1c157585a645dca4c960086032793899d05Tobin Ehlis    bool skip = PreCallValidateQueueWaitIdle(dev_data, queue, &queue_state);
47289867daedbf52debc77d6568162ee21e071699b80Chris Forbes    lock.unlock();
4729cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
47304a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueueWaitIdle(queue);
47314273a1c157585a645dca4c960086032793899d05Tobin Ehlis    if (VK_SUCCESS == result) {
4732e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.lock();
4733e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        PostCallRecordQueueWaitIdle(dev_data, queue_state);
4734e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.unlock();
47354273a1c157585a645dca4c960086032793899d05Tobin Ehlis    }
47365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
47375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47398767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic bool PreCallValidateDeviceWaitIdle(layer_data *dev_data) {
4740cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.device_wait_idle) return false;
47418767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = false;
47428767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
47438767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
47448767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
47458767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    return skip;
47468767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
47478767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
47488767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic void PostCallRecordDeviceWaitIdle(layer_data *dev_data) {
47498767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
47508767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        RetireWorkOnQueue(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
47518767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
47528767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
47538767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
475489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL DeviceWaitIdle(VkDevice device) {
475556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4756b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
47578767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = PreCallValidateDeviceWaitIdle(dev_data);
4758b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4759cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
47604a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.DeviceWaitIdle(device);
47618767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    if (VK_SUCCESS == result) {
47628767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.lock();
47638767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        PostCallRecordDeviceWaitIdle(dev_data);
47648767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.unlock();
47658767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
47665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
47675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47691d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic bool PreCallValidateDestroyFence(layer_data *dev_data, VkFence fence, FENCE_NODE **fence_node, VK_OBJECT *obj_struct) {
47709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *fence_node = GetFenceNode(dev_data, fence);
47717a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski    *obj_struct = {reinterpret_cast<uint64_t &>(fence), kVulkanObjectTypeFence};
4772cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_fence) return false;
47731d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = false;
47741d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (*fence_node) {
47751d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        if ((*fence_node)->state == FENCE_INFLIGHT) {
47761d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
4777208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                            (uint64_t)(fence), __LINE__, VALIDATION_ERROR_00173, "DS", "Fence 0x%" PRIx64 " is in use. %s",
4778208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                            (uint64_t)(fence), validation_error_map[VALIDATION_ERROR_00173]);
47791d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        }
47801d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
47811d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    return skip;
47821d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis}
47831d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
47841d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic void PostCallRecordDestroyFence(layer_data *dev_data, VkFence fence) { dev_data->fenceMap.erase(fence); }
47851d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
478689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
478756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
47881d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    // Common data objects used pre & post call
47891d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    FENCE_NODE *fence_node = nullptr;
47901d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    VK_OBJECT obj_struct;
4791b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
47921d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = PreCallValidateDestroyFence(dev_data, fence, &fence_node, &obj_struct);
47931344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
47941d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (!skip) {
47951d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.unlock();
47964a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyFence(device, fence, pAllocator);
47971d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.lock();
47981d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        PostCallRecordDestroyFence(dev_data, fence);
47991d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
48005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4802c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic bool PreCallValidateDestroySemaphore(layer_data *dev_data, VkSemaphore semaphore, SEMAPHORE_NODE **sema_node,
4803c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis                                            VK_OBJECT *obj_struct) {
48049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sema_node = GetSemaphoreNode(dev_data, semaphore);
48057a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski    *obj_struct = {reinterpret_cast<uint64_t &>(semaphore), kVulkanObjectTypeSemaphore};
4806cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_semaphore) return false;
4807c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = false;
4808c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    if (*sema_node) {
4809c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sema_node, *obj_struct, VALIDATION_ERROR_00199);
4810c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    }
4811c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    return skip;
4812c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis}
4813c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
4814c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic void PostCallRecordDestroySemaphore(layer_data *dev_data, VkSemaphore sema) { dev_data->semaphoreMap.erase(sema); }
4815c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
4816bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
481756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4818c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    SEMAPHORE_NODE *sema_node;
4819c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    VK_OBJECT obj_struct;
4820e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
4821c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = PreCallValidateDestroySemaphore(dev_data, semaphore, &sema_node, &obj_struct);
4822eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis    if (!skip) {
4823eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        lock.unlock();
48244a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySemaphore(device, semaphore, pAllocator);
4825c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        lock.lock();
4826c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        PostCallRecordDestroySemaphore(dev_data, semaphore);
482799d938c90c2f000ee73fb13513dacf84ffa5651fMark Mueller    }
48285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
48304710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic bool PreCallValidateDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE **event_state, VK_OBJECT *obj_struct) {
48319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *event_state = GetEventNode(dev_data, event);
48327a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski    *obj_struct = {reinterpret_cast<uint64_t &>(event), kVulkanObjectTypeEvent};
4833cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_event) return false;
4834d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = false;
4835d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    if (*event_state) {
4836d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *event_state, *obj_struct, VALIDATION_ERROR_00213);
4837d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    }
4838d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    return skip;
4839d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
4840d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
48414710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic void PostCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
484239c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, event_state->cb_bindings, obj_struct);
4843d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    dev_data->eventMap.erase(event);
4844d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
4845d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
484689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
484756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
48484710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    EVENT_STATE *event_state = nullptr;
4849d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    VK_OBJECT obj_struct;
4850b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4851d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = PreCallValidateDestroyEvent(dev_data, event, &event_state, &obj_struct);
4852f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
4853f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
48544a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyEvent(device, event, pAllocator);
4855d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        lock.lock();
4856405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (event != VK_NULL_HANDLE) {
4857405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyEvent(dev_data, event, event_state, obj_struct);
4858405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
4859f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
48605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
486283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlisstatic bool PreCallValidateDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE **qp_state,
486383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis                                            VK_OBJECT *obj_struct) {
48649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *qp_state = GetQueryPoolNode(dev_data, query_pool);
48657a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski    *obj_struct = {reinterpret_cast<uint64_t &>(query_pool), kVulkanObjectTypeQueryPool};
4866cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_query_pool) return false;
486783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = false;
486883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    if (*qp_state) {
486983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *qp_state, *obj_struct, VALIDATION_ERROR_01012);
487083c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    }
487183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    return skip;
487283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
487383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
4874bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void PostCallRecordDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE *qp_state,
4875bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VK_OBJECT obj_struct) {
487683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    invalidateCommandBuffers(dev_data, qp_state->cb_bindings, obj_struct);
487783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    dev_data->queryPoolMap.erase(query_pool);
487883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
487983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
4880bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
488156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
488283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    QUERY_POOL_NODE *qp_state = nullptr;
488383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    VK_OBJECT obj_struct;
4884ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
488583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = PreCallValidateDestroyQueryPool(dev_data, queryPool, &qp_state, &obj_struct);
4886f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
4887f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
48884a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyQueryPool(device, queryPool, pAllocator);
488983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        lock.lock();
4890405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (queryPool != VK_NULL_HANDLE) {
4891405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyQueryPool(dev_data, queryPool, qp_state, obj_struct);
4892405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
4893f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
48945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48959fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic bool PreCallValidateGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
48969fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               uint32_t query_count, VkQueryResultFlags flags,
48979fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
48989fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (auto cmd_buffer : dev_data->globalInFlightCmdBuffers) {
48999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb = GetCBNode(dev_data, cmd_buffer);
49009fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        for (auto query_state_pair : cb->queryToStateMap) {
49019fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            (*queries_in_flight)[query_state_pair.first].push_back(cmd_buffer);
49025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
49035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_query_pool_results) return false;
49059fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = false;
49069fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
49079fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
49089fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
49099fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
49109fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
4911ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski            // Available and in flight
49129fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
49139fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
49149fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
49159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
49169fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
49179fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair == cb->waitedEventsBeforeQueryReset.end()) {
49189fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
49199fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
49209fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is in flight.",
49219fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        (uint64_t)(query_pool), first_query + i);
4922ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                    }
4923ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
4924ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable and in flight
49259fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
49269fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                       !query_state_pair->second) {
4927ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // TODO : Can there be the same query in use by multiple command buffers in flight?
4928ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                bool make_available = false;
49299fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
49309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
49319fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    make_available |= cb->queryToStateMap[query];
4932ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
4933ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) {
49349fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
49359fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
49369fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
49379fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    (uint64_t)(query_pool), first_query + i);
49385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
4939ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable
49409fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair != dev_data->queryToStateMap.end() && !query_state_pair->second) {
49419fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
49429fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
49439fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
49449fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                (uint64_t)(query_pool), first_query + i);
49459fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                // Uninitialized
49469fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair == dev_data->queryToStateMap.end()) {
49479fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
49489fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
49499fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64
49509fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                " with index %d as data has not been collected for this index.",
49519fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                (uint64_t)(query_pool), first_query + i);
49525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
49535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
49545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
49559fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return skip;
49569fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
49579fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
49589fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic void PostCallRecordGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
49599fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              uint32_t query_count,
49609fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
49619fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
49629fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
49639fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
49649fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
49659fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
49669fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            // Available and in flight
49679fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
49689fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
49699fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
49709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
49719fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
49729fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair != cb->waitedEventsBeforeQueryReset.end()) {
49739fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        for (auto event : query_event_pair->second) {
49749fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                            dev_data->eventMap[event].needsSignaled = true;
49759fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        }
49769fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    }
49779fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                }
49789fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            }
49799fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        }
49809fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    }
49819fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
49829fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
49839fdee42cd357379efb9aa27f90beb75d1f824955Tobin EhlisVKAPI_ATTR VkResult VKAPI_CALL GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
49849fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                                   size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags) {
498556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
49869fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    unordered_map<QueryObject, vector<VkCommandBuffer>> queries_in_flight;
49879fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
49889fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = PreCallValidateGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, flags, &queries_in_flight);
4989b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4990cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
49919fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    VkResult result =
49929fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        dev_data->dispatch_table.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
49939fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.lock();
49949fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    PostCallRecordGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, &queries_in_flight);
49959fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.unlock();
49969fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return result;
49975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4999825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if given ranges intersect, else false
5000825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Prereq : For both ranges, range->end - range->start > 0. This case should have already resulted
5001825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  in an error so not checking that here
5002825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// pad_ranges bool indicates a linear and non-linear comparison which requires padding
50033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski// In the case where padding is required, if an alias is encountered then a validation error is reported and skip
50043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski//  may be set by the callback function so caller should merge in skip value if padding case is possible.
50052ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton// This check can be skipped by passing skip_checks=true, for call sites outside the validation path.
50063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinskistatic bool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, MEMORY_RANGE const *range2, bool *skip,
50072ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton                            bool skip_checks) {
50083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    *skip = false;
5009825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_start = range1->start;
5010825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_end = range1->end;
5011825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_start = range2->start;
5012825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_end = range2->end;
5013825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    VkDeviceSize pad_align = 1;
5014825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (range1->linear != range2->linear) {
5015825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        pad_align = dev_data->phys_dev_properties.properties.limits.bufferImageGranularity;
5016825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
5017cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_end & ~(pad_align - 1)) < (r2_start & ~(pad_align - 1))) return false;
5018cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_start & ~(pad_align - 1)) > (r2_end & ~(pad_align - 1))) return false;
501947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
50202ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton    if (!skip_checks && (range1->linear != range2->linear)) {
502153ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        // In linear vs. non-linear case, warn of aliasing
5022825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_linear_str = range1->linear ? "Linear" : "Non-linear";
5023825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_type_str = range1->image ? "image" : "buffer";
5024825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_linear_str = range2->linear ? "linear" : "non-linear";
5025825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_type_str = range2->image ? "image" : "buffer";
5026825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto obj_type = range1->image ? VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT : VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;
50273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        *skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, obj_type, range1->handle, 0,
50283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                         MEMTRACK_INVALID_ALIASING, "MEM", "%s %s 0x%" PRIx64 " is aliased with %s %s 0x%" PRIx64
50293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           " which may indicate a bug. For further info refer to the "
50303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "Buffer-Image Granularity section of the Vulkan specification. "
50313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "(https://www.khronos.org/registry/vulkan/specs/1.0-extensions/"
50323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "xhtml/vkspec.html#resources-bufferimagegranularity)",
50333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                         r1_linear_str, r1_type_str, range1->handle, r2_linear_str, r2_type_str, range2->handle);
503447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
5035825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Ranges intersect
5036825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    return true;
503747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
5038623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis// Simplified rangesIntersect that calls above function to check range1 for intersection with offset & end addresses
5039c3340a06ecac4d7b9540592cae339f8fc224d0b1Mark Lobodzinskibool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, VkDeviceSize offset, VkDeviceSize end) {
5040825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Create a local MEMORY_RANGE struct to wrap offset/size
5041825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    MEMORY_RANGE range_wrap;
5042825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Synch linear with range1 to avoid padding and potential validation error case
5043825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.linear = range1->linear;
5044825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.start = offset;
5045cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    range_wrap.end = end;
5046825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    bool tmp_bool;
50472ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton    return rangesIntersect(dev_data, range1, &range_wrap, &tmp_bool, true);
5048825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5049cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given mem_info, set all ranges valid that intersect [offset-end] range
5050cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// TODO : For ranges where there is no alias, we may want to create new buffer ranges that are valid
5051cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlisstatic void SetMemRangesValid(layer_data const *dev_data, DEVICE_MEM_INFO *mem_info, VkDeviceSize offset, VkDeviceSize end) {
5052cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    bool tmp_bool = false;
5053f6e16b28b808a342cb92768001afa2cfeee08a11Tobin Ehlis    MEMORY_RANGE map_range = {};
5054cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.linear = true;
5055cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.start = offset;
5056cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.end = end;
5057cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    for (auto &handle_range_pair : mem_info->bound_ranges) {
50582ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &handle_range_pair.second, &map_range, &tmp_bool, false)) {
5059cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : WARN here if tmp_bool true?
5060cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            handle_range_pair.second.valid = true;
5061cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        }
5062cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    }
5063cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis}
50640ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
50650ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info,
50660ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                      VkDeviceSize memoryOffset, VkMemoryRequirements memRequirements, bool is_image,
50670ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                      bool is_linear, const char *api_name) {
50680ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    bool skip = false;
50690ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
50700ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    MEMORY_RANGE range;
50710ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.image = is_image;
50720ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.handle = handle;
50730ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.linear = is_linear;
50740ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.valid = mem_info->global_valid;
50750ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.memory = mem_info->mem;
50760ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.start = memoryOffset;
50770ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.size = memRequirements.size;
50780ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.end = memoryOffset + memRequirements.size - 1;
50790ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.aliases.clear();
50800ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
50810ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    // Check for aliasing problems.
50820ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    for (auto &obj_range_pair : mem_info->bound_ranges) {
50830ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto check_range = &obj_range_pair.second;
50840ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        bool intersection_error = false;
50852ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &range, check_range, &intersection_error, false)) {
50860ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= intersection_error;
50870ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            range.aliases.insert(check_range);
50880ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
50890ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    }
50900ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
50910ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    if (memoryOffset >= mem_info->alloc_info.allocationSize) {
50920ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        UNIQUE_VALIDATION_ERROR_CODE error_code = is_image ? VALIDATION_ERROR_00805 : VALIDATION_ERROR_00793;
50930ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
50940ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       reinterpret_cast<uint64_t &>(mem_info->mem), __LINE__, error_code, "MEM",
50950ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
50960ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       "), memoryOffset=0x%" PRIxLEAST64 " must be less than the memory allocation size 0x%" PRIxLEAST64 ". %s",
50970ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       api_name, reinterpret_cast<uint64_t &>(mem_info->mem), handle, memoryOffset,
50980ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       mem_info->alloc_info.allocationSize, validation_error_map[error_code]);
50990ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    }
51000ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
51010ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    return skip;
51020ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
51030ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
5104825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Object with given handle is being bound to memory w/ given mem_info struct.
5105825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Track the newly bound memory range with given memoryOffset
5106825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Also scan any previous ranges, track aliased ranges with new range, and flag an error if a linear
5107825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  and non-linear range incorrectly overlap.
5108825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if an error is flagged and the user callback returns "true", otherwise false
5109825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_image indicates an image object, otherwise handle is for a buffer
5110825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_linear indicates a buffer or linear image
51110ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info, VkDeviceSize memoryOffset,
51120ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                              VkMemoryRequirements memRequirements, bool is_image, bool is_linear) {
51135360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    MEMORY_RANGE range;
5114825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5115825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.image = is_image;
511647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.handle = handle;
5117825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.linear = is_linear;
5118f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis    range.valid = mem_info->global_valid;
5119825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.memory = mem_info->mem;
512047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.start = memoryOffset;
5121825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.size = memRequirements.size;
512247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.end = memoryOffset + memRequirements.size - 1;
51235360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    range.aliases.clear();
51245360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // Update Memory aliasing
512575f4c8cec0996021a4258b9bf920a9e0fea4eac1Tobin 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
51265360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // inserted into map before loop to get the final ptr, then we may enter loop when not needed & we check range against itself
51275360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    std::unordered_set<MEMORY_RANGE *> tmp_alias_ranges;
5128825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto &obj_range_pair : mem_info->bound_ranges) {
5129825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto check_range = &obj_range_pair.second;
51305360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        bool intersection_error = false;
51312ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &range, check_range, &intersection_error, true)) {
5132825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis            range.aliases.insert(check_range);
51335360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis            tmp_alias_ranges.insert(check_range);
5134825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        }
5135825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
51365360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    mem_info->bound_ranges[handle] = std::move(range);
51375360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    for (auto tmp_range : tmp_alias_ranges) {
51385360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        tmp_range->aliases.insert(&mem_info->bound_ranges[handle]);
51395360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    }
5140825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (is_image)
5141825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.insert(handle);
5142825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    else
5143825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.insert(handle);
514447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
514547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
51460ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info,
51470ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                           VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, bool is_linear,
51480ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                           const char *api_name) {
51490ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    return ValidateInsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(image), mem_info, mem_offset, mem_reqs, true, is_linear,
51500ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                     api_name);
51510ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
51520ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
51530ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                   VkMemoryRequirements mem_reqs, bool is_linear) {
51540ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    InsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(image), mem_info, mem_offset, mem_reqs, true, is_linear);
5155825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5156825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
51570ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info,
51580ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                            VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, const char *api_name) {
51590ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    return ValidateInsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(buffer), mem_info, mem_offset, mem_reqs, false, true,
51600ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                     api_name);
51610ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
51620ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
51630ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                    VkMemoryRequirements mem_reqs) {
51640ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    InsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(buffer), mem_info, mem_offset, mem_reqs, false, true);
5165825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5166825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5167825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Remove MEMORY_RANGE struct for give handle from bound_ranges of mem_info
5168825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  is_image indicates if handle is for image or buffer
5169825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  This function will also remove the handle-to-index mapping from the appropriate
5170825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  map and clean up any aliases for range being removed.
5171825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic void RemoveMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info, bool is_image) {
5172825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto erase_range = &mem_info->bound_ranges[handle];
5173825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto alias_range : erase_range->aliases) {
5174825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        alias_range->aliases.erase(erase_range);
517547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
51765360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    erase_range->aliases.clear();
5177825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    mem_info->bound_ranges.erase(handle);
51781cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    if (is_image) {
5179825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.erase(handle);
51801cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    } else {
5181825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.erase(handle);
51821cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    }
518347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
518447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
5185842b2d28ded1c6e2c38491a81213d0e1d1b7295aMark Lobodzinskivoid RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, false); }
5186825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
51878c59133586421be878d393799b30044497f77727Mark Lobodzinskivoid RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, true); }
5188825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5189bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
519056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5191e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
5192e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    VK_OBJECT obj_struct;
5193b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5194e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    bool skip = PreCallValidateDestroyBuffer(dev_data, buffer, &buffer_state, &obj_struct);
5195e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    if (!skip) {
5196b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
51974a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBuffer(device, buffer, pAllocator);
5198e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        lock.lock();
5199405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (buffer != VK_NULL_HANDLE) {
5200405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBuffer(dev_data, buffer, buffer_state, obj_struct);
5201405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
520247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
52035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5205bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
520656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5207f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
52088e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    BUFFER_VIEW_STATE *buffer_view_state = nullptr;
52098e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    VK_OBJECT obj_struct;
5210a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
52118e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    // Validate state before calling down chain, update common data if we'll be calling down chain
52128e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    bool skip = PreCallValidateDestroyBufferView(dev_data, bufferView, &buffer_view_state, &obj_struct);
521338e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis    if (!skip) {
521438e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis        lock.unlock();
52154a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBufferView(device, bufferView, pAllocator);
52168e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis        lock.lock();
5217405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (bufferView != VK_NULL_HANDLE) {
5218405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBufferView(dev_data, bufferView, buffer_view_state, obj_struct);
5219405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
52205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
52215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
52232a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
522456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
52251facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    IMAGE_STATE *image_state = nullptr;
52262a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    VK_OBJECT obj_struct;
52272a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
52282a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    bool skip = PreCallValidateDestroyImage(dev_data, image, &image_state, &obj_struct);
52292a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    if (!skip) {
5230f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        lock.unlock();
52314a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImage(device, image, pAllocator);
52322a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        lock.lock();
5233405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (image != VK_NULL_HANDLE) {
5234405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImage(dev_data, image, image_state, obj_struct);
5235405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
52365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
52375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
52394261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinskistatic bool ValidateMemoryTypes(const layer_data *dev_data, const DEVICE_MEM_INFO *mem_info, const uint32_t memory_type_bits,
5240f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                const char *funcName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
52413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5242de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis    if (((1 << mem_info->alloc_info.memoryTypeIndex) & memory_type_bits) == 0) {
52433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
52443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       reinterpret_cast<const uint64_t &>(mem_info->mem), __LINE__, msgCode, "MT",
52453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "%s(): MemoryRequirements->memoryTypeBits (0x%X) for this object type are not compatible with the memory "
52463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "type (0x%X) of this memory object 0x%" PRIx64 ". %s",
52473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       funcName, memory_type_bits, mem_info->alloc_info.memoryTypeIndex,
52483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       reinterpret_cast<const uint64_t &>(mem_info->mem), validation_error_map[msgCode]);
52494261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    }
52503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
52514261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski}
52524261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski
5253160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic bool PreCallValidateBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
5254160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                            VkDeviceSize memoryOffset) {
52559207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    bool skip = false;
52565cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
5257160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
52589207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // Track objects tied to memory
52599207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        uint64_t buffer_handle = reinterpret_cast<uint64_t &>(buffer);
52607a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip = ValidateSetMemBinding(dev_data, mem, buffer_handle, kVulkanObjectTypeBuffer, "vkBindBufferMemory()");
52612eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (!buffer_state->memory_requirements_checked) {
52622eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // There's not an explicit requirement in the spec to call vkGetBufferMemoryRequirements() prior to calling
52639207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // BindBufferMemory, but it's implied in that memory being bound must conform with VkMemoryRequirements from
52649207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // vkGetBufferMemoryRequirements()
52659207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
52669207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle, __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
52679207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): Binding memory to buffer 0x%" PRIxLEAST64
52689207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but vkGetBufferMemoryRequirements() has not been called on that buffer.",
52699207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle);
52702eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // Make the call for them so we can verify the state
52712eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.unlock();
52729207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            dev_data->dispatch_table.GetBufferMemoryRequirements(dev_data->device, buffer, &buffer_state->requirements);
52732eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.lock();
52742eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        }
527547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
52760ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Validate bound memory range information
52779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
527857fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
52790ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= ValidateInsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements,
52800ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                                    "vkBindBufferMemory()");
52819207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, buffer_state->requirements.memoryTypeBits, "vkBindBufferMemory()",
52829207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                                        VALIDATION_ERROR_00797);
528347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
528447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
52852c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate memory requirements alignment
528616769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(memoryOffset, buffer_state->requirements.alignment) != 0) {
5287f60e41965223825191505eebc96491bb52e494a2Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5288f60e41965223825191505eebc96491bb52e494a2Cort Stratton                            buffer_handle, __LINE__, VALIDATION_ERROR_02174, "DS",
52899207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64
52909207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but must be an integer multiple of the "
52919207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
52929207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
52939207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            memoryOffset, buffer_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_02174]);
52942c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
5295ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5296160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements size
5297160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        if (buffer_state->requirements.size > (mem_info->alloc_info.allocationSize - memoryOffset)) {
5298160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5299160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            buffer_handle, __LINE__, VALIDATION_ERROR_02175, "DS",
5300160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindBufferMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
5301160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be at least as large as "
5302160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
5303160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
5304160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            mem_info->alloc_info.allocationSize - memoryOffset, buffer_state->requirements.size,
5305160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            validation_error_map[VALIDATION_ERROR_02175]);
5306160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
5307160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
53082c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate device limits alignments
5309ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        static const VkBufferUsageFlagBits usage_list[3] = {
5310ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
5311bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT};
5312bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *memory_type[3] = {"texel", "uniform", "storage"};
5313bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *offset_name[3] = {"minTexelBufferOffsetAlignment", "minUniformBufferOffsetAlignment",
5314bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             "minStorageBufferOffsetAlignment"};
5315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
53169207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // TODO:  vk_validation_stats.py cannot abide braces immediately preceding or following a validation error enum
5317cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format off
53180ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        static const UNIQUE_VALIDATION_ERROR_CODE msgCode[3] = { VALIDATION_ERROR_00794, VALIDATION_ERROR_00795,
53190ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            VALIDATION_ERROR_00796 };
5320cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format on
5321ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5322ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        // Keep this one fresh!
5323ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        const VkDeviceSize offset_requirement[3] = {
5324ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment,
5325ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
5326bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment};
53278718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        VkBufferUsageFlags usage = dev_data->bufferMap[buffer].get()->createInfo.usage;
5328ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5329ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        for (int i = 0; i < 3; i++) {
5330ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            if (usage & usage_list[i]) {
533116769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                if (SafeModulo(memoryOffset, offset_requirement[i]) != 0) {
53329207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                    skip |= log_msg(
5333f60e41965223825191505eebc96491bb52e494a2Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, buffer_handle,
5334cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, msgCode[i], "DS", "vkBindBufferMemory(): %s memoryOffset is 0x%" PRIxLEAST64
5335cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    " but must be a multiple of "
5336cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    "device limit %s 0x%" PRIxLEAST64 ". %s",
5337cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        memory_type[i], memoryOffset, offset_name[i], offset_requirement[i], validation_error_map[msgCode[i]]);
5338ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                }
53392c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves            }
53402c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
53415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
53429207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    return skip;
53439207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
53449207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
5345160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic void PostCallRecordBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
5346160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                           VkDeviceSize memoryOffset) {
53479207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (buffer_state) {
5348160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
53490ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Track bound memory range information
53500ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto mem_info = GetMemObjInfo(dev_data, mem);
53510ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        if (mem_info) {
53520ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            InsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements);
53530ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
53540ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
5355c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
5356c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        uint64_t buffer_handle = reinterpret_cast<uint64_t &>(buffer);
53577a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        SetMemBinding(dev_data, mem, buffer_handle, kVulkanObjectTypeBuffer, "vkBindBufferMemory()");
5358c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
53599207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.mem = mem;
53609207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.offset = memoryOffset;
53619207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.size = buffer_state->requirements.size;
53629207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    }
53639207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
53649207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
53659207132ef623d47fcbdfeb9ebc796eade35a2f4cCort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
53669207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
53679207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
5368160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    auto buffer_state = GetBufferState(dev_data, buffer);
5369160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    bool skip = PreCallValidateBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
53709207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (!skip) {
53714a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.BindBufferMemory(device, buffer, mem, memoryOffset);
53729207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        if (result == VK_SUCCESS) {
5373160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            PostCallRecordBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
53749207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        }
53755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
53765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
53775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5379bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
5380bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       VkMemoryRequirements *pMemoryRequirements) {
538156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
538215caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
53839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
538415caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (buffer_state) {
538515caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        buffer_state->requirements = *pMemoryRequirements;
53862eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        buffer_state->memory_requirements_checked = true;
538715caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
53885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5390bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
539156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
539215caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetImageMemoryRequirements(device, image, pMemoryRequirements);
53939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, image);
539415caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (image_state) {
539515caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        image_state->requirements = *pMemoryRequirements;
53962eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        image_state->memory_requirements_checked = true;
539715caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
53985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5399593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
5400bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
540156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5402f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
5403f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    IMAGE_VIEW_STATE *image_view_state = nullptr;
5404f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    VK_OBJECT obj_struct;
5405a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5406f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    bool skip = PreCallValidateDestroyImageView(dev_data, imageView, &image_view_state, &obj_struct);
5407d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    if (!skip) {
5408d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis        lock.unlock();
54094a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImageView(device, imageView, pAllocator);
5410f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis        lock.lock();
5411405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (imageView != VK_NULL_HANDLE) {
5412405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImageView(dev_data, imageView, image_view_state, obj_struct);
5413405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5414d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    }
54155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5417bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyShaderModule(VkDevice device, VkShaderModule shaderModule,
5418bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               const VkAllocationCallbacks *pAllocator) {
541956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5420918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
5421b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
542251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->shaderModuleMap.erase(shaderModule);
5423b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5424918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
542551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->dispatch_table.DestroyShaderModule(device, shaderModule, pAllocator);
54265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54284c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool PreCallValidateDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE **pipeline_state,
54298bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                           VK_OBJECT *obj_struct) {
543094165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *pipeline_state = getPipelineState(dev_data, pipeline);
54317a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski    *obj_struct = {reinterpret_cast<uint64_t &>(pipeline), kVulkanObjectTypePipeline};
5432cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_pipeline) return false;
54338bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = false;
54348bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    if (*pipeline_state) {
54351803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *pipeline_state, *obj_struct, VALIDATION_ERROR_00555);
54368bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    }
54378bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    return skip;
54388bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
54398bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
54404c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void PostCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
54418bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                          VK_OBJECT obj_struct) {
54428bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    // Any bound cmd buffers are now invalid
544339c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, pipeline_state->cb_bindings, obj_struct);
54448bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    dev_data->pipelineMap.erase(pipeline);
54458bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
54468bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
5447bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
544856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
54494c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pipeline_state = nullptr;
54508bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    VK_OBJECT obj_struct;
5451e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
54528bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = PreCallValidateDestroyPipeline(dev_data, pipeline, &pipeline_state, &obj_struct);
5453f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5454f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
54554a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyPipeline(device, pipeline, pAllocator);
54568bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis        lock.lock();
5457405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (pipeline != VK_NULL_HANDLE) {
5458405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyPipeline(dev_data, pipeline, pipeline_state, obj_struct);
5459405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5460f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
54615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5463bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout,
5464bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
546556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5466e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
54676792ea7cc0ce5fa64b7bd6c946460608cbda91c7Tobin Ehlis    dev_data->pipelineLayoutMap.erase(pipelineLayout);
5468e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    lock.unlock();
5469e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
54704a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineLayout(device, pipelineLayout, pAllocator);
54715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5473d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic bool PreCallValidateDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE **sampler_state,
5474806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                          VK_OBJECT *obj_struct) {
54759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sampler_state = GetSamplerState(dev_data, sampler);
54767a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski    *obj_struct = {reinterpret_cast<uint64_t &>(sampler), kVulkanObjectTypeSampler};
5477cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_sampler) return false;
5478806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = false;
5479806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    if (*sampler_state) {
5480806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sampler_state, *obj_struct, VALIDATION_ERROR_00837);
5481806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    }
5482806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    return skip;
5483806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5484806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5485d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic void PostCallRecordDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE *sampler_state,
5486806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                         VK_OBJECT obj_struct) {
5487806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    // Any bound cmd buffers are now invalid
5488cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (sampler_state) invalidateCommandBuffers(dev_data, sampler_state->cb_bindings, obj_struct);
5489806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    dev_data->samplerMap.erase(sampler);
5490806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5491806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5492bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
549356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5494d31a44af6da568692a73201825459689c9431867Tobin Ehlis    SAMPLER_STATE *sampler_state = nullptr;
5495806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    VK_OBJECT obj_struct;
549656f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5497806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = PreCallValidateDestroySampler(dev_data, sampler, &sampler_state, &obj_struct);
5498f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5499f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
55004a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySampler(device, sampler, pAllocator);
5501806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        lock.lock();
5502405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (sampler != VK_NULL_HANDLE) {
5503405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroySampler(dev_data, sampler, sampler_state, obj_struct);
5504405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5505f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
55065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
550879c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlisstatic void PostCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDescriptorSetLayout ds_layout) {
550979c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->descriptorSetLayoutMap.erase(ds_layout);
551079c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis}
551179c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis
5512bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
5513bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator) {
551456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
551579c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->dispatch_table.DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
551679c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
551779c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    PostCallRecordDestroyDescriptorSetLayout(dev_data, descriptorSetLayout);
55185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5520c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic bool PreCallValidateDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool pool,
5521a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                 DESCRIPTOR_POOL_STATE **desc_pool_state, VK_OBJECT *obj_struct) {
55229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *desc_pool_state = GetDescriptorPoolState(dev_data, pool);
55237a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski    *obj_struct = {reinterpret_cast<uint64_t &>(pool), kVulkanObjectTypeDescriptorPool};
5524cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_descriptor_pool) return false;
5525c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = false;
5526c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (*desc_pool_state) {
55271803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *desc_pool_state, *obj_struct, VALIDATION_ERROR_00901);
5528c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5529c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    return skip;
5530c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5531c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5532c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic void PostCallRecordDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool descriptorPool,
5533a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                DESCRIPTOR_POOL_STATE *desc_pool_state, VK_OBJECT obj_struct) {
5534c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Any bound cmd buffers are now invalid
553539c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, desc_pool_state->cb_bindings, obj_struct);
5536c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Free sets that were in this pool
5537c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    for (auto ds : desc_pool_state->sets) {
5538c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        freeDescriptorSet(dev_data, ds);
5539c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5540c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    dev_data->descriptorPoolMap.erase(descriptorPool);
5541c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5542c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5543bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
5544bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
554556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5546a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    DESCRIPTOR_POOL_STATE *desc_pool_state = nullptr;
5547c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    VK_OBJECT obj_struct;
5548c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5549c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = PreCallValidateDestroyDescriptorPool(dev_data, descriptorPool, &desc_pool_state, &obj_struct);
5550c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (!skip) {
5551c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.unlock();
5552c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        dev_data->dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
5553c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.lock();
5554405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptorPool != VK_NULL_HANDLE) {
5555405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyDescriptorPool(dev_data, descriptorPool, desc_pool_state, obj_struct);
5556405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5557c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
55585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski// Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip result
5560bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If this is a secondary command buffer, then make sure its primary is also in-flight
5561bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If primary is not in-flight, then remove secondary from global in-flight set
5562bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// This function is only valid at a point when cmdBuffer is being reset or freed
5563cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action,
5564cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
55653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5566bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    if (dev_data->globalInFlightCmdBuffers.count(cb_node->commandBuffer)) {
5567bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        // Primary CB or secondary where primary is also in-flight is an error
5568bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_SECONDARY) ||
5569bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis            (dev_data->globalInFlightCmdBuffers.count(cb_node->primaryCommandBuffer))) {
55703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
55713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<const uint64_t &>(cb_node->commandBuffer), __LINE__, error_code, "DS",
55723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Attempt to %s command buffer (0x%p) which is in use. %s", action, cb_node->commandBuffer,
55733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            validation_error_map[error_code]);
5574bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
5575bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
55763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
5577bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
5578a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
5579bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Iterate over all cmdBuffers in given commandPool and verify that each is not in use
5580cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool, const char *action,
5581cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                        UNIQUE_VALIDATION_ERROR_CODE error_code) {
55823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5583a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
5584a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        if (dev_data->globalInFlightCmdBuffers.count(cmd_buffer)) {
55853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= checkCommandBufferInFlight(dev_data, GetCBNode(dev_data, cmd_buffer), action, error_code);
5586bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
5587bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
55883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
5589bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
55905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5591a01b5eb150981aad061238e64b173d0da8c11140Chris Forbesstatic void clearCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool) {
5592a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
5593a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
5594a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes    }
5595a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes}
5596a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
5597bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
5598bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
559956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
56003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5601b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5602c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
56035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < commandBufferCount; i++) {
56049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
56055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Delete CB information structure, and remove from commandBufferMap
56069f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
56073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= checkCommandBufferInFlight(dev_data, cb_node, "free", VALIDATION_ERROR_00096);
5608c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        }
5609c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    }
5610c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
56113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
5612c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
56139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
5614c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    for (uint32_t i = 0; i < commandBufferCount; i++) {
56159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
5616c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        // Delete CB information structure, and remove from commandBufferMap
56179f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
56189f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->globalInFlightCmdBuffers.erase(cb_node->commandBuffer);
56195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // reset prior to delete for data clean-up
56209f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            resetCB(dev_data, cb_node->commandBuffer);
56219f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->commandBufferMap.erase(cb_node->commandBuffer);
56229f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            delete cb_node;
56235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
56245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
56255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Remove commandBuffer reference from commandPoolMap
5626c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        pPool->commandBuffers.remove(pCommandBuffers[i]);
56275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5628b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5629e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
56304a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
56315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
563389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
5634bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
563556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
56365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
56374a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
56385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
56395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5640b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
56415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
56425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
56435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
56445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
56455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
564789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
564889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
564956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
56500c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    bool skip = false;
56510c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (pCreateInfo && pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
56520c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        if (!dev_data->enabled_features.pipelineStatisticsQuery) {
56530c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
56540c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            __LINE__, VALIDATION_ERROR_01006, "DS",
56550c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "Query pool with type VK_QUERY_TYPE_PIPELINE_STATISTICS created on a device "
56560c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "with VkDeviceCreateInfo.pEnabledFeatures.pipelineStatisticsQuery == VK_FALSE. %s",
56570c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            validation_error_map[VALIDATION_ERROR_01006]);
56580c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        }
56590c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
56600c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis
56610c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
56620c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (!skip) {
56630c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        result = dev_data->dispatch_table.CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
56640c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
56655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
5666b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5667eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        QUERY_POOL_NODE *qp_node = &dev_data->queryPoolMap[*pQueryPool];
5668eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        qp_node->createInfo = *pCreateInfo;
56695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
56705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
56715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
56735f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic bool PreCallValidateDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE **cp_state) {
56749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cp_state = GetCommandPoolNode(dev_data, pool);
5675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_command_pool) return false;
56765f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = false;
56775f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (*cp_state) {
56785f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        // Verify that command buffers in pool are complete (not in-flight)
56795f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        skip |= checkCommandBuffersInFlight(dev_data, *cp_state, "destroy command pool with", VALIDATION_ERROR_00077);
56805f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
56815f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    return skip;
56825f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
56835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
56845f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic void PostCallRecordDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE *cp_state) {
56859f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandBufferMap
56865f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    clearCommandBuffersInFlight(dev_data, cp_state);
56875f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    for (auto cb : cp_state->commandBuffers) {
56889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, cb);
56897b34d10b918c1f69e7252174965c6a7a7c35ae05Chris Forbes        clear_cmd_buf_and_mem_references(dev_data, cb_node);
5690d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // Remove references to this cb_node prior to delete
5691d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // TODO : Need better solution here, resetCB?
56927165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        for (auto obj : cb_node->object_bindings) {
56937165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski            removeCommandBufferBinding(dev_data, &obj, cb_node);
56947165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        }
5695d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        for (auto framebuffer : cb_node->framebuffers) {
56969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
5697cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(cb_node);
5698d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        }
5699cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        dev_data->commandBufferMap.erase(cb);  // Remove this command buffer
5700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        delete cb_node;                        // delete CB info structure
5701a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    }
57025f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    dev_data->commandPoolMap.erase(pool);
57035f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
5704e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
57055f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis// Destroy commandPool along with all of the commandBuffers allocated from that pool
57065f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
570756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
57085f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    COMMAND_POOL_NODE *cp_state = nullptr;
57095f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
57105f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = PreCallValidateDestroyCommandPool(dev_data, commandPool, &cp_state);
57115f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (!skip) {
57125f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.unlock();
57135f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        dev_data->dispatch_table.DestroyCommandPool(device, commandPool, pAllocator);
57145f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.lock();
5715405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (commandPool != VK_NULL_HANDLE) {
5716405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyCommandPool(dev_data, commandPool, cp_state);
5717405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
57185f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
57195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5721bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
572256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
57233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5724400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
57251ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
57269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
57273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= checkCommandBuffersInFlight(dev_data, pPool, "reset command pool with", VALIDATION_ERROR_00072);
57281ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    lock.unlock();
5729a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes
57303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
57315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
57324a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandPool(device, commandPool, flags);
57335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
57345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Reset all of the CBs allocated from this pool
57355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
57361ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.lock();
5737a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        clearCommandBuffersInFlight(dev_data, pPool);
5738a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        for (auto cmdBuffer : pPool->commandBuffers) {
5739a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes            resetCB(dev_data, cmdBuffer);
57405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
57411ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.unlock();
57425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
57435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
57445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
574689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
574756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
57483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5749b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
57505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < fenceCount; ++i) {
57519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, pFences[i]);
5752090da73358f71ba026e2474a822fecf55267d166Chris Forbes        if (pFence && pFence->state == FENCE_INFLIGHT) {
57533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
57543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pFences[i]), __LINE__, VALIDATION_ERROR_00183, "DS",
57553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Fence 0x%" PRIx64 " is in use. %s", reinterpret_cast<const uint64_t &>(pFences[i]),
57563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_00183]);
57575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
57585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5759b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5760090da73358f71ba026e2474a822fecf55267d166Chris Forbes
57613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
5762090da73358f71ba026e2474a822fecf55267d166Chris Forbes
57634a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetFences(device, fenceCount, pFences);
5764090da73358f71ba026e2474a822fecf55267d166Chris Forbes
5765090da73358f71ba026e2474a822fecf55267d166Chris Forbes    if (result == VK_SUCCESS) {
5766090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.lock();
5767090da73358f71ba026e2474a822fecf55267d166Chris Forbes        for (uint32_t i = 0; i < fenceCount; ++i) {
57689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pFence = GetFenceNode(dev_data, pFences[i]);
5769090da73358f71ba026e2474a822fecf55267d166Chris Forbes            if (pFence) {
5770090da73358f71ba026e2474a822fecf55267d166Chris Forbes                pFence->state = FENCE_UNSIGNALED;
5771090da73358f71ba026e2474a822fecf55267d166Chris Forbes            }
5772090da73358f71ba026e2474a822fecf55267d166Chris Forbes        }
5773090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.unlock();
5774090da73358f71ba026e2474a822fecf55267d166Chris Forbes    }
5775090da73358f71ba026e2474a822fecf55267d166Chris Forbes
57765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
57775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5779e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis// For given cb_nodes, invalidate them and track object causing invalidation
57800a4087f99558069e9f6a437ff2dbb5a9c1c22ccaTobin Ehlisvoid invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj) {
5781e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    for (auto cb_node : cb_nodes) {
578239c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        if (cb_node->state == CB_RECORDING) {
578339c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5784fefa20333f94ea75877cca53d0631542cd9d0432Tobin Ehlis                    (uint64_t)(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
5785226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "Invalidating a command buffer that's currently being recorded: 0x%p.", cb_node->commandBuffer);
578639c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        }
5787e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->state = CB_INVALID;
5788e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->broken_bindings.push_back(obj);
5789e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    }
5790e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis}
5791e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis
5792c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool PreCallValidateDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer,
5793c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis                                              FRAMEBUFFER_STATE **framebuffer_state, VK_OBJECT *obj_struct) {
57949a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *framebuffer_state = GetFramebufferState(dev_data, framebuffer);
57957a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski    *obj_struct = {reinterpret_cast<uint64_t &>(framebuffer), kVulkanObjectTypeFramebuffer};
5796cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_framebuffer) return false;
5797728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = false;
5798728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (*framebuffer_state) {
5799728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *framebuffer_state, *obj_struct, VALIDATION_ERROR_00422);
5800728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    }
5801728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    return skip;
5802728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
5803728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
5804c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void PostCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
5805728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis                                             VK_OBJECT obj_struct) {
580639c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, framebuffer_state->cb_bindings, obj_struct);
5807728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    dev_data->frameBufferMap.erase(framebuffer);
5808728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
5809728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
5810bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
581156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5812c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    FRAMEBUFFER_STATE *framebuffer_state = nullptr;
5813728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    VK_OBJECT obj_struct;
5814b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5815728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = PreCallValidateDestroyFramebuffer(dev_data, framebuffer, &framebuffer_state, &obj_struct);
5816728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (!skip) {
5817728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.unlock();
5818728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        dev_data->dispatch_table.DestroyFramebuffer(device, framebuffer, pAllocator);
5819728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.lock();
5820405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (framebuffer != VK_NULL_HANDLE) {
5821405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyFramebuffer(dev_data, framebuffer, framebuffer_state, obj_struct);
5822405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
58235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58260ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic bool PreCallValidateDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE **rp_state,
58270ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                             VK_OBJECT *obj_struct) {
58289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *rp_state = GetRenderPassState(dev_data, render_pass);
58297a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski    *obj_struct = {reinterpret_cast<uint64_t &>(render_pass), kVulkanObjectTypeRenderPass};
5830cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_renderpass) return false;
58310ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = false;
58320ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    if (*rp_state) {
58330ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *rp_state, *obj_struct, VALIDATION_ERROR_00393);
58340ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    }
58350ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    return skip;
58360ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
58370ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
58380ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic void PostCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
58390ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                            VK_OBJECT obj_struct) {
584039c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, rp_state->cb_bindings, obj_struct);
58410ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    dev_data->renderPassMap.erase(render_pass);
58420ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
58430ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
5844bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
584556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58460ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    RENDER_PASS_STATE *rp_state = nullptr;
58470ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    VK_OBJECT obj_struct;
5848e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
58490ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = PreCallValidateDestroyRenderPass(dev_data, renderPass, &rp_state, &obj_struct);
5850a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    if (!skip) {
5851a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis        lock.unlock();
58524a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
58530ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        lock.lock();
5854405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (renderPass != VK_NULL_HANDLE) {
5855405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyRenderPass(dev_data, renderPass, rp_state, obj_struct);
5856405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5857a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    }
58585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
586089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
586189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
586256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58633683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
58643683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    bool skip = PreCallValidateCreateBuffer(dev_data, pCreateInfo);
58653683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    lock.unlock();
58663683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
58673683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
58684a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
58695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
58713683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.lock();
58723683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBuffer(dev_data, pCreateInfo, pBuffer);
58733683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.unlock();
58745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
587889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
587989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
588056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58818c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
58823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateCreateBufferView(dev_data, pCreateInfo);
58838c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
58843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
58854a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBufferView(device, pCreateInfo, pAllocator, pView);
58865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
58878c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
58883683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBufferView(dev_data, pCreateInfo, pView);
58898c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
58905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58948dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski// Access helper functions for external modules
5895d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkFormatProperties *GetFormatProperties(core_validation::layer_data *device_data, VkFormat format) {
5896d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkFormatProperties *format_properties = new VkFormatProperties;
5897d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
5898d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
5899d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, format_properties);
5900d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return format_properties;
59018dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
59028dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
5903d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkImageFormatProperties *GetImageFormatProperties(core_validation::layer_data *device_data, VkFormat format,
5904d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageType image_type, VkImageTiling tiling, VkImageUsageFlags usage,
5905d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageCreateFlags flags) {
5906d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkImageFormatProperties *image_format_properties = new VkImageFormatProperties;
5907d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
5908d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
5909d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceImageFormatProperties(device_data->physical_device, format, image_type, tiling,
5910d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                                         usage, flags, image_format_properties);
5911d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return image_format_properties;
59128dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
59138dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
59147a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlisconst debug_report_data *GetReportData(const core_validation::layer_data *device_data) { return device_data->report_data; }
59158dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
59168dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinskiconst VkPhysicalDeviceProperties *GetPhysicalDeviceProperties(core_validation::layer_data *device_data) {
59178dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    return &device_data->phys_dev_props;
59188dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
59198dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
59208c59133586421be878d393799b30044497f77727Mark Lobodzinskiconst CHECK_DISABLED *GetDisables(core_validation::layer_data *device_data) { return &device_data->instance_data->disabled; }
59218c59133586421be878d393799b30044497f77727Mark Lobodzinski
59228c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> *GetImageMap(core_validation::layer_data *device_data) {
59238c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageMap;
59248c59133586421be878d393799b30044497f77727Mark Lobodzinski}
59258c59133586421be878d393799b30044497f77727Mark Lobodzinski
59268c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *GetImageSubresourceMap(core_validation::layer_data *device_data) {
59278c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageSubresourceMap;
59288c59133586421be878d393799b30044497f77727Mark Lobodzinski}
59298c59133586421be878d393799b30044497f77727Mark Lobodzinski
59308c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *GetImageLayoutMap(layer_data *device_data) {
59318c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageLayoutMap;
59328c59133586421be878d393799b30044497f77727Mark Lobodzinski}
59338c59133586421be878d393799b30044497f77727Mark Lobodzinski
59340db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlisstd::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const *GetImageLayoutMap(layer_data const *device_data) {
59350db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis    return &device_data->imageLayoutMap;
59360db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis}
59370db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis
59383683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>> *GetBufferMap(layer_data *device_data) {
59393683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferMap;
59403683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
59413683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
59423683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>> *GetBufferViewMap(layer_data *device_data) {
59433683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferViewMap;
59443683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
59453683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
59461c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinskistd::unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>> *GetImageViewMap(layer_data *device_data) {
59471c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski    return &device_data->imageViewMap;
59481c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski}
59491c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski
5950d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst PHYS_DEV_PROPERTIES_NODE *GetPhysDevProperties(const layer_data *device_data) {
59516a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    return &device_data->phys_dev_properties;
59526a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski}
59536a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski
59545f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinskiconst VkPhysicalDeviceFeatures *GetEnabledFeatures(const layer_data *device_data) {
59555f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski    return &device_data->enabled_features;
59565f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski}
59575f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski
59580e2296e24065d02615ee87561bbb80af414a1ddfMike Schuchardtconst devExts *GetDeviceExtensions(const layer_data *device_data) { return &device_data->device_extensions; }
59590e2296e24065d02615ee87561bbb80af414a1ddfMike Schuchardt
596089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
596189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
59628dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
596356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
59648dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    bool skip = PreCallValidateCreateImage(dev_data, pCreateInfo, pAllocator, pImage);
59658dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    if (!skip) {
59668dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski        result = dev_data->dispatch_table.CreateImage(device, pCreateInfo, pAllocator, pImage);
59678dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    }
59685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5969b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5970920311b6aa5614a545cad59521770d0898a75d65Mark Lobodzinski        PostCallRecordCreateImage(dev_data, pCreateInfo, pImage);
59715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
59725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
59735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59758c07a094dc9cc4afb6b62181f341c12b9e969041Mark YoungVKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
59768c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
597756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
59788c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
5979e3effabf8e97cae8e006477806ceaca62e4f2ce7Tobin Ehlis    bool skip = PreCallValidateCreateImageView(dev_data, pCreateInfo);
59808c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
5981cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
59824a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateImageView(device, pCreateInfo, pAllocator, pView);
59835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
59848c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
598579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        PostCallRecordCreateImageView(dev_data, pCreateInfo, *pView);
59868c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
59875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5988bb6624cb996175d8945190886a200e720b3871efChris Forbes
59895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
59905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5992bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo,
5993bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
599456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
59954a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFence(device, pCreateInfo, pAllocator, pFence);
59965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5997b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5998a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        auto &fence_node = dev_data->fenceMap[*pFence];
59998988ad37ea5a054ff2ae3cbe4b767ae6c13cf48bChris Forbes        fence_node.fence = *pFence;
6000a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        fence_node.createInfo = *pCreateInfo;
6001cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        fence_node.state = (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) ? FENCE_RETIRED : FENCE_UNSIGNALED;
60025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO handle pipeline caches
600789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
600889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
600956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60104a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
60115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6014bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache,
6015bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkAllocationCallbacks *pAllocator) {
601656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60174a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineCache(device, pipelineCache, pAllocator);
60185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6020bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize,
6021bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    void *pData) {
602256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60234a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
60245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6027bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount,
6028bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   const VkPipelineCache *pSrcCaches) {
602956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60304a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
60315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60343d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis// utility function to set collective state for pipeline
60354c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisvoid set_pipeline_state(PIPELINE_STATE *pPipe) {
60363d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // If any attachment used by this pipeline has blendEnable, set top-level blendEnable
60373d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->graphicsPipelineCI.pColorBlendState) {
60383d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        for (size_t i = 0; i < pPipe->attachments.size(); ++i) {
60393d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (VK_TRUE == pPipe->attachments[i].blendEnable) {
60403d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                if (((pPipe->attachments[i].dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
60413d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
60423d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
60433d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
60443d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
60453d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
60463d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
60473d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
60483d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    pPipe->blendConstantsEnabled = true;
60493d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                }
60503d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            }
60513d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        }
60523d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
60533d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis}
60543d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis
6055daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinskibool validate_dual_src_blend_feature(layer_data *device_data, PIPELINE_STATE *pipe_state) {
6056daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    bool skip = false;
6057daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    if (pipe_state->graphicsPipelineCI.pColorBlendState) {
6058daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski        for (size_t i = 0; i < pipe_state->attachments.size(); ++i) {
6059daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            if (!device_data->enabled_features.dualSrcBlend) {
6060daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                if ((pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
6061daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
6062daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
6063daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA) ||
6064daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
6065daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
6066daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
6067daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA)) {
6068daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    skip |=
6069daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
6070daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                reinterpret_cast<uint64_t &>(pipe_state->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
6071daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                "CmdBindPipeline: vkPipeline (0x%" PRIxLEAST64 ") attachment[" PRINTF_SIZE_T_SPECIFIER
6072daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                "] has a dual-source blend factor but this device feature is not enabled.",
6073daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                reinterpret_cast<uint64_t &>(pipe_state->pipeline), i);
6074daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                }
6075daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            }
6076daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski        }
6077daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    }
6078daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    return skip;
6079daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski}
6080daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski
608148b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinskistatic bool PreCallCreateGraphicsPipelines(layer_data *device_data, uint32_t count,
608248b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski                                           const VkGraphicsPipelineCreateInfo *create_infos, vector<PIPELINE_STATE *> &pipe_state) {
608348b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    bool skip = false;
6084bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    instance_layer_data *instance_data =
608556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
608648b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
608748b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    for (uint32_t i = 0; i < count; i++) {
608848b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski        skip |= verifyPipelineCreateState(device_data, pipe_state, i);
608978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        if (create_infos[i].pVertexInputState != NULL) {
609078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            for (uint32_t j = 0; j < create_infos[i].pVertexInputState->vertexAttributeDescriptionCount; j++) {
609178b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormat format = create_infos[i].pVertexInputState->pVertexAttributeDescriptions[j].format;
609278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                // Internal call to get format info.  Still goes through layers, could potentially go directly to ICD.
609378b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormatProperties properties;
609478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, &properties);
609578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                if ((properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0) {
609678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                    skip |= log_msg(
609778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
609878b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        __LINE__, VALIDATION_ERROR_01413, "IMAGE",
609978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "vkCreateGraphicsPipelines: pCreateInfo[%d].pVertexInputState->vertexAttributeDescriptions[%d].format "
610078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "(%s) is not a supported vertex buffer format. %s",
610178b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        i, j, string_VkFormat(format), validation_error_map[VALIDATION_ERROR_01413]);
610278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                }
610378b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            }
610478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        }
610548b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    }
610648b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    return skip;
610748b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski}
610848b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
6109bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6110bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
6111bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
61125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO What to do with pipelineCache?
61135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // The order of operations here is a little convoluted but gets the job done
61144c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    //  1. Pipeline create state is first shadowed into PIPELINE_STATE struct
61155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  2. Create state is then validated (which uses flags setup during shadowing)
61165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
611742486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    bool skip = false;
61185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
611942486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    vector<PIPELINE_STATE *> pipe_state(count);
612056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6123b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
61245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
612642486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i] = new PIPELINE_STATE;
612742486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->initGraphicsPipeline(&pCreateInfos[i]);
61289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        pipe_state[i]->render_pass_ci.initialize(GetRenderPassState(dev_data, pCreateInfos[i].renderPass)->createInfo.ptr());
612942486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
61305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
613142486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    skip |= PreCallCreateGraphicsPipelines(dev_data, count, pCreateInfos, pipe_state);
61325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6133c70226063be6148056ceeccf835175a1fd59f24fChris Forbes    if (skip) {
6134c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        for (i = 0; i < count; i++) {
6135c70226063be6148056ceeccf835175a1fd59f24fChris Forbes            delete pipe_state[i];
61361ab616b32d4e5b7d62d4a8c41b0c03ea335ab845Chris Forbes            pPipelines[i] = VK_NULL_HANDLE;
6137c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        }
61387a456d188475c23b566334be45dc0489b2789653Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
61397a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
61407a456d188475c23b566334be45dc0489b2789653Chris Forbes
61417a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6142bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6143bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
61447a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
61457a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
614661943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
614761943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            delete pipe_state[i];
6148bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
614961943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            pipe_state[i]->pipeline = pPipelines[i];
615061943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            dev_data->pipelineMap[pipe_state[i]->pipeline] = pipe_state[i];
615161943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        }
61525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6153c70226063be6148056ceeccf835175a1fd59f24fChris Forbes
61545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6157bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6158bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkComputePipelineCreateInfo *pCreateInfos,
6159bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
61600108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes    bool skip = false;
61615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
61634c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    vector<PIPELINE_STATE *> pPipeState(count);
616456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6167b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
61685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
61695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Verify compute stage bits
61705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Create and initialize internal tracking data structure
61724c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i] = new PIPELINE_STATE;
61734c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i]->initComputePipeline(&pCreateInfos[i]);
6174c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis        pPipeState[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
61755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Add Compute Pipeline Verification
6177e446ad08318228362ef35d73e7a0636075cb3636Chris Forbes        skip |= validate_compute_pipeline(dev_data, pPipeState[i]);
61780108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes        // skip |= verifyPipelineCreateState(dev_data, pPipeState[i]);
61795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61817a456d188475c23b566334be45dc0489b2789653Chris Forbes    if (skip) {
61825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < count; i++) {
61835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Clean up any locally allocated data structures
61844c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis            delete pPipeState[i];
6185fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipelines[i] = VK_NULL_HANDLE;
61865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
61875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
61885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61897a456d188475c23b566334be45dc0489b2789653Chris Forbes
61907a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6191bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6192bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
61937a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
61947a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
6195fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
6196fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            delete pPipeState[i];
6197bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
6198fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipeState[i]->pipeline = pPipelines[i];
6199fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            dev_data->pipelineMap[pPipeState[i]->pipeline] = pPipeState[i];
6200fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        }
62017a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
62027a456d188475c23b566334be45dc0489b2789653Chris Forbes
62035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
620689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
620789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
620856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62094a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSampler(device, pCreateInfo, pAllocator, pSampler);
62105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6211b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6212d31a44af6da568692a73201825459689c9431867Tobin Ehlis        dev_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_STATE>(new SAMPLER_STATE(pSampler, pCreateInfo));
62135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62170c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic bool PreCallValidateCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info) {
6218cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.create_descriptor_set_layout) return false;
62190c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    return cvdescriptorset::DescriptorSetLayout::ValidateCreateInfo(dev_data->report_data, create_info);
62200c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
62210c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
62220c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic void PostCallRecordCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info,
62230c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis                                                    VkDescriptorSetLayout set_layout) {
62243f1d2ba6852cf6b1bb4e1f06d690293565108e2cTobin Ehlis    // TODO: Convert this to unique_ptr to avoid leaks
62250c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    dev_data->descriptorSetLayoutMap[set_layout] = new cvdescriptorset::DescriptorSetLayout(create_info, set_layout);
62260c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
62270c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
6228bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
6229bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator,
6230bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VkDescriptorSetLayout *pSetLayout) {
623156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62320c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
62330c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
62340c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    bool skip = PreCallValidateCreateDescriptorSetLayout(dev_data, pCreateInfo);
62350c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    if (!skip) {
62360c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        lock.unlock();
62370c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        result = dev_data->dispatch_table.CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
62380c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        if (VK_SUCCESS == result) {
62390c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            lock.lock();
62400c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            PostCallRecordCreateDescriptorSetLayout(dev_data, pCreateInfo, *pSetLayout);
62410c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        }
62425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62469e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Used by CreatePipelineLayout and CmdPushConstants.
62479e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Note that the index argument is optional and only used by CreatePipelineLayout.
62489e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultzstatic bool validatePushConstantRange(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
62499e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz                                      const char *caller_name, uint32_t index = 0) {
6250cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.push_constant_range) return false;
62519e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    uint32_t const maxPushConstantsSize = dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize;
62523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
62539e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Check that offset + size don't exceed the max.
62549e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Prevent arithetic overflow here by avoiding addition and testing in this order.
62559e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset >= maxPushConstantsSize) || (size > maxPushConstantsSize - offset)) {
62569e24d8153ab63bc3ac08b5a1517c203930b5de91Karl 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.
62579e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6258e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (offset >= maxPushConstantsSize) {
62593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
62603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, VALIDATION_ERROR_00877, "DS",
62613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with offset %u that "
62623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "exceeds this device's maxPushConstantSize of %u. %s",
62633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00877]);
6264e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
6265e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (size > maxPushConstantsSize - offset) {
62663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
6267df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6268df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, VALIDATION_ERROR_00880, "DS",
6269cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u and size %u that "
6270cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
6271e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                            caller_name, index, offset, size, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00880]);
6272e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
62739e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
62744527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (offset >= maxPushConstantsSize) {
62753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
62763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, VALIDATION_ERROR_00991, "DS",
62773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with offset %u that "
62783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "exceeds this device's maxPushConstantSize of %u. %s",
62793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00991]);
62804527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
62814527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size > maxPushConstantsSize - offset) {
62823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
6283df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6284df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, VALIDATION_ERROR_00992, "DS",
6285cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u and size %u that "
6286cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
62874527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            caller_name, index, offset, size, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00992]);
62884527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
62899e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
62903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
62913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
62929e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
62939e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
62949e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // size needs to be non-zero and a multiple of 4.
62959e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((size == 0) || ((size & 0x3) != 0)) {
62969e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6297891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size == 0) {
62983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
62993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, VALIDATION_ERROR_00878, "DS",
63003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
63013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be greater than zero. %s",
63023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_00878]);
6303891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
6304891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size & 0x3) {
63053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
63063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, VALIDATION_ERROR_00879, "DS",
63073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
63083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be a multiple of 4. %s",
63093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_00879]);
6310891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
63119e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
63124527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size == 0) {
63133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
63143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, VALIDATION_ERROR_01000, "DS",
63153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
63163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be greater than zero. %s",
63173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_01000]);
63184527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
63194527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size & 0x3) {
63203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
63213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, VALIDATION_ERROR_00990, "DS",
63223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
63233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be a multiple of 4. %s",
63243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_00990]);
63254527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
63269e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
63273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
63283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
63299e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
63309e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
63319e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // offset needs to be a multiple of 4.
63329e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset & 0x3) != 0) {
63339e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
63343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
63353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, VALIDATION_ERROR_02521, "DS",
63363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s call has push constants index %u with "
63373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "offset %u. Offset must be a multiple of 4. %s",
63383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            caller_name, index, offset, validation_error_map[VALIDATION_ERROR_02521]);
63399e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
63403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
63413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, VALIDATION_ERROR_00989, "DS",
63423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s call has push constants with "
63433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "offset %u. Offset must be a multiple of 4. %s",
63443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            caller_name, offset, validation_error_map[VALIDATION_ERROR_00989]);
63459e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
63463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
63473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
63489e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
63495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
63515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6353bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
635489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                    const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
63553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
635656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6357bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // TODO : Add checks for VALIDATION_ERRORS 865-870
63589e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Push Constant Range checks
635907a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    uint32_t i, j;
63605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
63613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validatePushConstantRange(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
63623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                          pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()", i);
63639e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == pCreateInfo->pPushConstantRanges[i].stageFlags) {
63643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
63653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, VALIDATION_ERROR_00882, "DS", "vkCreatePipelineLayout() call has no stageFlags set. %s",
63663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_00882]);
63679e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
63689e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
63693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
637007a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz
6371bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl 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.
637207a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
637307a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz        for (j = i + 1; j < pCreateInfo->pushConstantRangeCount; ++j) {
6374bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz            if (0 != (pCreateInfo->pPushConstantRanges[i].stageFlags & pCreateInfo->pPushConstantRanges[j].stageFlags)) {
63753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
63763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, VALIDATION_ERROR_00871, "DS",
63773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "vkCreatePipelineLayout() Duplicate stage flags found in ranges %d and %d. %s", i, j,
63783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                validation_error_map[VALIDATION_ERROR_00871]);
63799e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz            }
63805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
63815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6382f73b2046273413ea1338dd714d67c39f8e0fa09eChris Forbes
63834a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
63845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6385b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
63865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
638769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        plNode.layout = *pPipelineLayout;
6388416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.set_layouts.resize(pCreateInfo->setLayoutCount);
63895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
63909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            plNode.set_layouts[i] = GetDescriptorSetLayout(dev_data, pCreateInfo->pSetLayouts[i]);
63915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6392416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.push_constant_ranges.resize(pCreateInfo->pushConstantRangeCount);
63935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
6394416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            plNode.push_constant_ranges[i] = pCreateInfo->pPushConstantRanges[i];
63955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
63965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6400bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
6401bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) {
640256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
64034a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
64045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6405a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis        DESCRIPTOR_POOL_STATE *pNewNode = new DESCRIPTOR_POOL_STATE(*pDescriptorPool, pCreateInfo);
64065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (NULL == pNewNode) {
64075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
64085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
6409a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                        "Out of memory while attempting to allocate DESCRIPTOR_POOL_STATE in vkCreateDescriptorPool()"))
64105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return VK_ERROR_VALIDATION_FAILED_EXT;
64115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
6412b9e992386a44404152747d66817a733aa127e281Jeremy Hayes            std::lock_guard<std::mutex> lock(global_lock);
64135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
64145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
64155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
64165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Need to do anything if pool create fails?
64175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
64195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6421bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
6422bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDescriptorPoolResetFlags flags) {
64237286e20c06011d3c6fa7edfbdbadd42bb6e8cc35Tobin Ehlis    // TODO : Add checks for VALIDATION_ERROR_00928
642456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
64254a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetDescriptorPool(device, descriptorPool, flags);
64265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6427b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
64285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        clearDescriptorPool(dev_data, device, descriptorPool, flags);
64295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
64315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64322c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes// Ensure the pool contains enough descriptors and descriptor sets to satisfy
6433789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// an allocation request. Fills common_data with the total number of descriptors of each type required,
6434789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// as well as DescriptorSetLayout ptrs used for later update.
64357f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlisstatic bool PreCallValidateAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
64367f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                  cvdescriptorset::AllocateDescriptorSetsData *common_data) {
64377a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    // Always update common data
64387a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    cvdescriptorset::UpdateAllocateDescriptorSetsData(dev_data, pAllocateInfo, common_data);
6439cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.allocate_descriptor_sets) return false;
64407e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All state checks for AllocateDescriptorSets is done in single function
64417a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    return cvdescriptorset::ValidateAllocateDescriptorSets(dev_data, pAllocateInfo, common_data);
64427e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis}
64437e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis// Allocation state was good and call down chain was made so update state based on allocating descriptor sets
64447e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlisstatic void PostCallRecordAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
64457f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 VkDescriptorSet *pDescriptorSets,
64467f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 const cvdescriptorset::AllocateDescriptorSetsData *common_data) {
64477e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All the updates are contained in a single cvdescriptorset function
64482c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    cvdescriptorset::PerformAllocateDescriptorSets(pAllocateInfo, pDescriptorSets, common_data, &dev_data->descriptorPoolMap,
6449b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                                                   &dev_data->setMap, dev_data);
64502c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes}
64512c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes
6452bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
6453bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkDescriptorSet *pDescriptorSets) {
645456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6455b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
64567f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    cvdescriptorset::AllocateDescriptorSetsData common_data(pAllocateInfo->descriptorSetCount);
64573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateAllocateDescriptorSets(dev_data, pAllocateInfo, &common_data);
6458b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6459d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
64603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
6461d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
64624a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
64636511ce241f7f210211e0c0e882f3c14889071f4dChris Forbes
64645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6465b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
64667f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis        PostCallRecordAllocateDescriptorSets(dev_data, pAllocateInfo, pDescriptorSets, &common_data);
6467b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
64685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
64705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6471cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Verify state before freeing DescriptorSets
6472cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic bool PreCallValidateFreeDescriptorSets(const layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6473cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                              const VkDescriptorSet *descriptor_sets) {
6474cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_descriptor_sets) return false;
64753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
6476cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // First make sure sets being destroyed are not currently in-use
6477405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    for (uint32_t i = 0; i < count; ++i) {
6478405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
64793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateIdleDescriptorSet(dev_data, descriptor_sets[i], "vkFreeDescriptorSets");
6480405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6481405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    }
6482cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
64839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6484a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    if (pool_state && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pool_state->createInfo.flags)) {
6485cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        // Can't Free from a NON_FREE pool
64863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
64873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t &>(pool), __LINE__, VALIDATION_ERROR_00922, "DS",
64883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
64893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT. %s",
64903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_00922]);
6491cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
64923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
6493cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
6494cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Sets have been removed from the pool so update underlying state
6495cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic void PostCallRecordFreeDescriptorSets(layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6496cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                             const VkDescriptorSet *descriptor_sets) {
64979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6498cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // Update available descriptor sets in pool
6499cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    pool_state->availableSets += count;
6500cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
6501cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // For each freed descriptor add its resources back into the pool as available and remove from pool and setMap
6502cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    for (uint32_t i = 0; i < count; ++i) {
6503405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
6504405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            auto descriptor_set = dev_data->setMap[descriptor_sets[i]];
6505405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            uint32_t type_index = 0, descriptor_count = 0;
6506405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            for (uint32_t j = 0; j < descriptor_set->GetBindingCount(); ++j) {
6507405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                type_index = static_cast<uint32_t>(descriptor_set->GetTypeFromIndex(j));
6508405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                descriptor_count = descriptor_set->GetDescriptorCountFromIndex(j);
6509405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                pool_state->availableDescriptorTypeCount[type_index] += descriptor_count;
6510405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            }
6511405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            freeDescriptorSet(dev_data, descriptor_set);
6512405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            pool_state->sets.erase(descriptor_set);
6513405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6514cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
6515cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
65165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6517bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
6518bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkDescriptorSet *pDescriptorSets) {
651956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
65205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Make sure that no sets being destroyed are in-flight
6521b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
65223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6523b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6524e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
65253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
65264a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
65275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6528b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
6529cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        PostCallRecordFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6530b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
65315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
65335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65346b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// TODO : This is a Proof-of-concept for core validation architecture
65356b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  Really we'll want to break out these functions to separate files but
65366b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  keeping it all together here to prove out design
65376b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PreCallValidate* handles validating all of the state prior to calling down chain to UpdateDescriptorSets()
65386b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic bool PreCallValidateUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
65396b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
65406b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkCopyDescriptorSet *pDescriptorCopies) {
6541cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.update_descriptor_sets) return false;
65426b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // First thing to do is perform map look-ups.
65436b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // NOTE : UpdateDescriptorSets is somewhat unique in that it's operating on a number of DescriptorSets
65446b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  so we can't just do a single map look-up up-front, but do them individually in functions below
65456b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis
65466b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Now make call(s) that validate state, but don't perform state updates in this function
65476b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Note, here DescriptorSets is unique in that we don't yet have an instance. Using a helper function in the
65486b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  namespace which will parse params and make calls into specific class instances
6549104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return cvdescriptorset::ValidateUpdateDescriptorSets(dev_data->report_data, dev_data, descriptorWriteCount, pDescriptorWrites,
6550104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis                                                         descriptorCopyCount, pDescriptorCopies);
65516b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
65526b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSets()
65536b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic void PostCallRecordUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
65546b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
65556b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkCopyDescriptorSet *pDescriptorCopies) {
6556104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    cvdescriptorset::PerformUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
65576b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                 pDescriptorCopies);
65586b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
65595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6560bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
6561bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
6562bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkCopyDescriptorSet *pDescriptorCopies) {
65636b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Only map look-up at top level is for device-level layer_data
656456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6565b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
65663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
65673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                    pDescriptorCopies);
6568b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
65693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
65704a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
65714a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                      pDescriptorCopies);
65726b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        lock.lock();
65736b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        // Since UpdateDescriptorSets() is void, nothing to check prior to updating state
65746b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        PostCallRecordUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
65756b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                           pDescriptorCopies);
65765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6579bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo,
6580bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkCommandBuffer *pCommandBuffer) {
658156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
65824a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
65835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6584b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::unique_lock<std::mutex> lock(global_lock);
65859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pPool = GetCommandPoolNode(dev_data, pCreateInfo->commandPool);
6586cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes
6587cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes        if (pPool) {
658872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
65895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to its commandPool map
6590cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes                pPool->commandBuffers.push_back(pCommandBuffer[i]);
65915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
65925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to map
65935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
65945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                resetCB(dev_data, pCommandBuffer[i]);
65955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->createInfo = *pCreateInfo;
65965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->device = device;
65975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
65985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6599b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
66005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6604883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis// Add bindings between the given cmd buffer & framebuffer and the framebuffer's children
6605c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void AddFramebufferBinding(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, FRAMEBUFFER_STATE *fb_state) {
66060245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis    addCommandBufferBinding(&fb_state->cb_bindings,
66077a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                            {reinterpret_cast<uint64_t &>(fb_state->framebuffer), kVulkanObjectTypeFramebuffer},
66080245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            cb_state);
6609883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    for (auto attachment : fb_state->attachments) {
6610883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        auto view_state = attachment.view_state;
6611883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (view_state) {
661203ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis            AddCommandBufferBindingImageView(dev_data, cb_state, view_state);
6613883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
66149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto rp_state = GetRenderPassState(dev_data, fb_state->createInfo.renderPass);
6615883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (rp_state) {
6616883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            addCommandBufferBinding(
6617883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis                &rp_state->cb_bindings,
66187a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                {reinterpret_cast<uint64_t &>(rp_state->renderPass), kVulkanObjectTypeRenderPass}, cb_state);
6619883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
6620883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    }
6621883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis}
6622883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis
6623bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
66243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
662556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6626b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
66275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate command buffer level
66289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
6629f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
66305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
6631a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        if (dev_data->globalInFlightCmdBuffers.count(commandBuffer)) {
66323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
66333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00103, "MEM",
66343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Calling vkBeginCommandBuffer() on active command buffer 0x%p before it has completed. "
66353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "You must check command buffer fence before this call. %s",
66363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            commandBuffer, validation_error_map[VALIDATION_ERROR_00103]);
66375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6638f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, cb_node);
6639f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
66405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary Command Buffer
66415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
66425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!pInfo) {
66433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
66445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
66454527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00106, "DS",
6646bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must have inheritance info. %s", commandBuffer,
6647bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_00106]);
66485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
66495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
66502c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    // Object_tracker makes sure these objects are valid
66512c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->renderPass);
66522c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->framebuffer);
66532c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    string errorString = "";
66549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto framebuffer = GetFramebufferState(dev_data, pInfo->framebuffer);
66552c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    if (framebuffer) {
66562c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        if ((framebuffer->createInfo.renderPass != pInfo->renderPass) &&
66572c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            !verify_renderpass_compatibility(dev_data, framebuffer->renderPassCreateInfo.ptr(),
66589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                             GetRenderPassState(dev_data, pInfo->renderPass)->createInfo.ptr(),
66592c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                             errorString)) {
66602c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            // renderPass that framebuffer was created with must be compatible with local renderPass
66613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
66623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
66633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00112, "DS",
66643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "vkBeginCommandBuffer(): Secondary Command "
66653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "Buffer (0x%p) renderPass (0x%" PRIxLEAST64
66663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            ") is incompatible w/ framebuffer "
66673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "(0x%" PRIxLEAST64 ") w/ render pass (0x%" PRIxLEAST64 ") due to: %s. %s",
66683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            commandBuffer, reinterpret_cast<const uint64_t &>(pInfo->renderPass),
66693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            reinterpret_cast<const uint64_t &>(pInfo->framebuffer),
66703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            reinterpret_cast<uint64_t &>(framebuffer->createInfo.renderPass), errorString.c_str(),
66713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            validation_error_map[VALIDATION_ERROR_00112]);
66725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
66732c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        // Connect this framebuffer and its children to this cmdBuffer
66742c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        AddFramebufferBinding(dev_data, cb_node, framebuffer);
66755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
66765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
66774527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                if ((pInfo->occlusionQueryEnable == VK_FALSE || dev_data->enabled_features.occlusionQueryPrecise == VK_FALSE) &&
66785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
66793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
66803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer),
66813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    __LINE__, VALIDATION_ERROR_00107, "DS",
66823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must not have "
66833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not "
66843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "support precise occlusion queries. %s",
66853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    commandBuffer, validation_error_map[VALIDATION_ERROR_00107]);
66865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
66875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
66885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
66899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto renderPass = GetRenderPassState(dev_data, pInfo->renderPass);
669016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                if (renderPass) {
6691fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    if (pInfo->subpass >= renderPass->createInfo.subpassCount) {
66923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
66933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
66943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        VALIDATION_ERROR_00111, "DS",
66953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        "vkBeginCommandBuffer(): Secondary Command Buffers (0x%p) must have a subpass index (%d) "
66963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        "that is less than the number of subpasses (%d). %s",
66973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        commandBuffer, pInfo->subpass, renderPass->createInfo.subpassCount,
66983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        validation_error_map[VALIDATION_ERROR_00111]);
66995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
67005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
67015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
67025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6703f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (CB_RECORDING == cb_node->state) {
67043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
67053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00103, "DS",
67063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkBeginCommandBuffer(): Cannot call Begin on command buffer (0x%p"
67073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") in the RECORDING state. Must first call vkEndCommandBuffer(). %s",
67083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            commandBuffer, validation_error_map[VALIDATION_ERROR_00103]);
6709347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        } else if (CB_RECORDED == cb_node->state || (CB_INVALID == cb_node->state && CMD_END == cb_node->last_cmd)) {
6710f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            VkCommandPool cmdPool = cb_node->createInfo.commandPool;
67119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pPool = GetCommandPoolNode(dev_data, cmdPool);
6712cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes            if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
67133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
67145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
67154527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00105, "DS",
6716226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "Call to vkBeginCommandBuffer() on command buffer (0x%p"
6717414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") attempts to implicitly reset cmdBuffer created from command pool (0x%" PRIxLEAST64
67184527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
67194527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            commandBuffer, (uint64_t)cmdPool, validation_error_map[VALIDATION_ERROR_00105]);
67205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
67215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            resetCB(dev_data, commandBuffer);
67225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
67235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Set updated state here in case implicit reset occurs above
6724f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->state = CB_RECORDING;
6725f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->beginInfo = *pBeginInfo;
6726f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->beginInfo.pInheritanceInfo) {
6727f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->inheritanceInfo = *(cb_node->beginInfo.pInheritanceInfo);
6728f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->beginInfo.pInheritanceInfo = &cb_node->inheritanceInfo;
6729888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            // If we are a secondary command-buffer and inheriting.  Update the items we should inherit.
6730f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) &&
6731f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                (cb_node->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
67329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                cb_node->activeRenderPass = GetRenderPassState(dev_data, cb_node->beginInfo.pInheritanceInfo->renderPass);
6733f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->activeSubpass = cb_node->beginInfo.pInheritanceInfo->subpass;
6734350841afb70bf8dcfc3c6ec6b66f0aaa639553a3Tobin Ehlis                cb_node->activeFramebuffer = cb_node->beginInfo.pInheritanceInfo->framebuffer;
6735f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->framebuffers.insert(cb_node->beginInfo.pInheritanceInfo->framebuffer);
6736888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            }
67375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
67385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6739b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
67415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
67425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67434a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.BeginCommandBuffer(commandBuffer, pBeginInfo);
6744400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
67455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
67465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
674889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL EndCommandBuffer(VkCommandBuffer commandBuffer) {
67493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
675056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6751b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
67544527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        if ((VK_COMMAND_BUFFER_LEVEL_PRIMARY == pCB->createInfo.level) ||
67554527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
6756fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // This needs spec clarification to update valid usage, see comments in PR:
6757fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/pull/516#discussion_r63013756
67583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= insideRenderPass(dev_data, pCB, "vkEndCommandBuffer()", VALIDATION_ERROR_00123);
6759fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop        }
67603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_END, "vkEndCommandBuffer()");
67611ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_END);
67625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto query : pCB->activeQueries) {
67633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
67643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00124, "DS",
67653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Ending command buffer with in progress query: queryPool 0x%" PRIx64 ", index %d. %s",
67663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            (uint64_t)(query.pool), query.index, validation_error_map[VALIDATION_ERROR_00124]);
67675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
67685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
6770b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
67710d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        auto result = dev_data->dispatch_table.EndCommandBuffer(commandBuffer);
6772b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
67735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (VK_SUCCESS == result) {
67745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->state = CB_RECORDED;
67755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
67760d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        return result;
67775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
67780d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
67795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6782bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
67833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
678456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6785b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkCommandPool cmdPool = pCB->createInfo.commandPool;
67889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, cmdPool);
6789cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes    if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
67903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
67913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00093, "DS",
67923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Attempt to reset command buffer (0x%p) created from command pool (0x%" PRIxLEAST64
67933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
67943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        commandBuffer, (uint64_t)cmdPool, validation_error_map[VALIDATION_ERROR_00093]);
67955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= checkCommandBufferInFlight(dev_data, pCB, "reset", VALIDATION_ERROR_00092);
6797b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
67994a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandBuffer(commandBuffer, flags);
68005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6801b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
6802a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes        dev_data->globalInFlightCmdBuffers.erase(commandBuffer);
68035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        resetCB(dev_data, commandBuffer);
6804b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
68055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
68065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
68075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
680893c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
6809bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
6810bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkPipeline pipeline) {
6811e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    bool skip = false;
681256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6813b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
6815e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    if (cb_state) {
6816baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindPipeline()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6817baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_00603);
681829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
68191ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_state, CMD_BINDPIPELINE);
6820e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (cb_state->activeRenderPass)) {
6821e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |=
68225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
68235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
6824414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "Incorrectly binding compute pipeline (0x%" PRIxLEAST64 ") during active RenderPass (0x%" PRIxLEAST64 ")",
6825e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                        (uint64_t)pipeline, (uint64_t)cb_state->activeRenderPass->renderPass);
68265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
68274527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        // TODO: VALIDATION_ERROR_00594 VALIDATION_ERROR_00596
68285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6829e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        PIPELINE_STATE *pipe_state = getPipelineState(dev_data, pipeline);
6830e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (pipe_state) {
6831e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            cb_state->lastBound[pipelineBindPoint].pipeline_state = pipe_state;
6832e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_cb_pso_status(cb_state, pipe_state);
6833e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_pipeline_state(pipe_state);
6834daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            skip |= validate_dual_src_blend_feature(dev_data, pipe_state);
68355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
6836e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
68374527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            (uint64_t)pipeline, __LINE__, VALIDATION_ERROR_00600, "DS",
68384527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "Attempt to bind Pipeline 0x%" PRIxLEAST64 " that doesn't exist! %s", (uint64_t)(pipeline),
68394527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            validation_error_map[VALIDATION_ERROR_00600]);
6840e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        }
6841e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        addCommandBufferBinding(&pipe_state->cb_bindings,
68427a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                {reinterpret_cast<uint64_t &>(pipeline), kVulkanObjectTypePipeline}, cb_state);
6843e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
6844e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            // Add binding for child renderpass
68459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto rp_state = GetRenderPassState(dev_data, pipe_state->graphicsPipelineCI.renderPass);
6846e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            if (rp_state) {
6847e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                addCommandBufferBinding(
6848e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                    &rp_state->cb_bindings,
68497a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                    {reinterpret_cast<uint64_t &>(rp_state->renderPass), kVulkanObjectTypeRenderPass}, cb_state);
6850e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            }
68515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
68525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6853b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6854cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
68555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6857bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
6858bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          const VkViewport *pViewports) {
68593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
686056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6861b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
68643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetViewport()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01446);
68653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()");
68661ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETVIEWPORTSTATE);
6867bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->viewportMask |= ((1u << viewportCount) - 1u) << firstViewport;
68685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6869b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
68703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
68715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6873bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
6874bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         const VkRect2D *pScissors) {
68753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
687656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6877b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
68803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetScissor()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01495);
68813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()");
68821ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSCISSORSTATE);
6883bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->scissorMask |= ((1u << scissorCount) - 1u) << firstScissor;
68845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6885b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
68863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
68875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
688989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
68903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
689156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6892b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
68953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetLineWidth()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01480);
68963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()");
68971ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETLINEWIDTHSTATE);
68985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_LINE_WIDTH_SET;
6899a27508babf63d50aea75883a3702979193c23683Mark Young
69004c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pPipeTrav = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline_state;
6901a27508babf63d50aea75883a3702979193c23683Mark Young        if (pPipeTrav != NULL && !isDynamic(pPipeTrav, VK_DYNAMIC_STATE_LINE_WIDTH)) {
69023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
69033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_01476, "DS",
69043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdSetLineWidth called but pipeline was created without VK_DYNAMIC_STATE_LINE_WIDTH "
69053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "flag.  This is undefined behavior and could be ignored. %s",
69063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_01476]);
6907a27508babf63d50aea75883a3702979193c23683Mark Young        } else {
69083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_SET, kVulkanObjectTypeCommandBuffer,
69093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    reinterpret_cast<uint64_t &>(commandBuffer), lineWidth);
6910a27508babf63d50aea75883a3702979193c23683Mark Young        }
69115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6912b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
69133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetLineWidth(commandBuffer, lineWidth);
69145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6916bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
6917bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           float depthBiasSlopeFactor) {
69183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
691956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6920b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
69225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
69233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetDepthBias()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01485);
69243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()");
6925434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        if ((depthBiasClamp != 0.0) && (!dev_data->enabled_features.depthBiasClamp)) {
69263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
69273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_01482, "DS",
69283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdSetDepthBias(): the depthBiasClamp device feature is disabled: the depthBiasClamp "
69293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "parameter must be set to 0.0. %s",
69303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_01482]);
6931434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
69323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        if (!skip) {
6933434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBIASSTATE);
6934434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            pCB->status |= CBSTATUS_DEPTH_BIAS_SET;
6935434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
69365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6937b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
69383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip)
69394a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
69405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
694289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
69433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
694456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6945b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
69475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
69483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetBlendConstants()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01553);
69493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()");
69501ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETBLENDSTATE);
69513d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        pCB->status |= CBSTATUS_BLEND_CONSTANTS_SET;
69525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6953b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
69543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetBlendConstants(commandBuffer, blendConstants);
69555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6957bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
69583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
695956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6960b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
69625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
69633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetDepthBounds()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01509);
69643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()");
69651ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBOUNDSSTATE);
69665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET;
69675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6968b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
69693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
69705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6972bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
6973bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    uint32_t compareMask) {
69743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
697556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6976b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
69785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
69793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilCompareMask()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01519);
69803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()");
69811ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREADMASKSTATE);
69825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET;
69835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6984b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
69853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
69865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6988bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
69893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
699056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6991b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
69935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
69943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilWriteMask()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01525);
69953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()");
69961ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILWRITEMASKSTATE);
69975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
69985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6999b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
70003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
70015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7003bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
70043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
700556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7006b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
70093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilReference()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01531);
70103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()");
70111ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREFERENCESTATE);
70125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET;
70135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7014b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
70153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilReference(commandBuffer, faceMask, reference);
70165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7018bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
7019bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
7020bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
7021bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const uint32_t *pDynamicOffsets) {
7022946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
702356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7024b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7025946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
7026946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
7027baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindDescriptorSets()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
7028baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_00985);
7029946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()");
7030ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        // Track total count of dynamic descriptor types to make sure we have an offset for each one
7031946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t total_dynamic_descriptors = 0;
7032946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        string error_string = "";
7033946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t last_set_index = firstSet + setCount - 1;
7034946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (last_set_index >= cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size()) {
7035946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
7036946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].dynamicOffsets.resize(last_set_index + 1);
7037946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        }
7038946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        auto old_final_bound_set = cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index];
7039ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        auto pipeline_layout = getPipelineLayout(dev_data, layout);
7040ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t set_idx = 0; set_idx < setCount; set_idx++) {
7041ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cvdescriptorset::DescriptorSet *descriptor_set = GetSetNode(dev_data, pDescriptorSets[set_idx]);
7042ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (descriptor_set) {
7043946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].pipeline_layout = *pipeline_layout;
7044946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[set_idx + firstSet] = descriptor_set;
7045946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
7046946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx], __LINE__,
7047946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                DRAWSTATE_NONE, "DS", "Descriptor Set 0x%" PRIxLEAST64 " bound on pipeline %s",
7048946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                (uint64_t)pDescriptorSets[set_idx], string_VkPipelineBindPoint(pipelineBindPoint));
7049ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                if (!descriptor_set->IsUpdated() && (descriptor_set->GetTotalDescriptorCount() != 0)) {
7050946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
7051946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx], __LINE__,
7052946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
7053946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "Descriptor Set 0x%" PRIxLEAST64
7054946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    " bound but it was never updated. You may want to either update it or not bind it.",
7055946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    (uint64_t)pDescriptorSets[set_idx]);
7056ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
7057ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
705812b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                if (!verify_set_layout_compatibility(descriptor_set, pipeline_layout, set_idx + firstSet, error_string)) {
7059946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7060946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx], __LINE__,
7061946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VALIDATION_ERROR_00974, "DS",
7062946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout "
7063946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "at index %u of pipelineLayout 0x%" PRIxLEAST64 " due to: %s. %s",
7064946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    set_idx, set_idx + firstSet, reinterpret_cast<uint64_t &>(layout), error_string.c_str(),
7065946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    validation_error_map[VALIDATION_ERROR_00974]);
70665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
7067ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7068946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                auto set_dynamic_descriptor_count = descriptor_set->GetDynamicDescriptorCount();
7069ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7070946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx].clear();
7071ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7072946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (set_dynamic_descriptor_count) {
7073ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    // First make sure we won't overstep bounds of pDynamicOffsets array
7074946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if ((total_dynamic_descriptors + set_dynamic_descriptor_count) > dynamicOffsetCount) {
7075946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7076946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
7077946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        __LINE__, DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
7078946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        "descriptorSet #%u (0x%" PRIxLEAST64
7079946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
7080946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        "array. There must be one dynamic offset for each dynamic descriptor being bound.",
7081946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        set_idx, (uint64_t)pDescriptorSets[set_idx], descriptor_set->GetDynamicDescriptorCount(),
7082946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        (dynamicOffsetCount - total_dynamic_descriptors));
7083ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    } else {  // Validate and store dynamic offsets with the set
7084ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Validate Dynamic Offset Minimums
7085946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        uint32_t cur_dyn_offset = total_dynamic_descriptors;
7086ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        for (uint32_t d = 0; d < descriptor_set->GetTotalDescriptorCount(); d++) {
7087ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
708816769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                                if (SafeModulo(
7089ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
7090ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
7091946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    skip |= log_msg(
7092ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7093ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_00978, "DS",
7094ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7095ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
7096ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
7097ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
7098ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        validation_error_map[VALIDATION_ERROR_00978]);
7099ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
7100ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
7101ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            } else if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
710216769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                                if (SafeModulo(
7103ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
7104ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
7105946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    skip |= log_msg(
7106ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7107ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_00978, "DS",
7108ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7109ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
7110ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
7111ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment,
7112ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        validation_error_map[VALIDATION_ERROR_00978]);
7113ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
7114ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
7115ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            }
711672d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        }
7117ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7118946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx] =
7119946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            std::vector<uint32_t>(pDynamicOffsets + total_dynamic_descriptors,
7120946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                  pDynamicOffsets + total_dynamic_descriptors + set_dynamic_descriptor_count);
7121ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Keep running total of dynamic descriptor count to verify at the end
7122946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        total_dynamic_descriptors += set_dynamic_descriptor_count;
712372d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    }
712472d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                }
7125ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            } else {
7126946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= log_msg(
7127ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
7128ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    (uint64_t)pDescriptorSets[set_idx], __LINE__, DRAWSTATE_INVALID_SET, "DS",
7129ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    "Attempt to bind descriptor set 0x%" PRIxLEAST64 " that doesn't exist!", (uint64_t)pDescriptorSets[set_idx]);
7130ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            }
7131946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            UpdateCmdBufferLastCmd(cb_state, CMD_BINDDESCRIPTORSETS);
7132ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update
7133ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (firstSet > 0) {  // Check set #s below the first bound set
7134ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                for (uint32_t i = 0; i < firstSet; ++i) {
7135946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if (cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] &&
713612b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                        !verify_set_layout_compatibility(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i],
7137946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                         pipeline_layout, i, error_string)) {
7138946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        skip |= log_msg(
7139ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
7140ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
7141946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS",
7142ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            "DescriptorSet 0x%" PRIxLEAST64
7143ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            " previously bound as set #%u was disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
7144946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i], i, (uint64_t)layout);
7145946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE;
71465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
71475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
71485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7149ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // Check if newly last bound set invalidates any remaining bound sets
7150946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            if ((cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (last_set_index)) {
7151946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (old_final_bound_set &&
715212b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                    !verify_set_layout_compatibility(old_final_bound_set, pipeline_layout, last_set_index, error_string)) {
7153946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    auto old_set = old_final_bound_set->GetSet();
7154946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
7155946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, reinterpret_cast<uint64_t &>(old_set), __LINE__,
7156946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    DRAWSTATE_NONE, "DS", "DescriptorSet 0x%" PRIxLEAST64
7157946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " previously bound as set #%u is incompatible with set 0x%" PRIxLEAST64
7158946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " newly bound as set #%u so set #%u and any subsequent sets were "
7159946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          "disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
7160946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    reinterpret_cast<uint64_t &>(old_set), last_set_index,
7161946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    (uint64_t)cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index],
7162946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    last_set_index, last_set_index + 1, (uint64_t)layout);
7163946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
7164ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
7165787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            }
7166ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
7167ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
7168946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (total_dynamic_descriptors != dynamicOffsetCount) {
7169946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7170946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00975, "DS",
7171946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
7172946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "is %u. It should exactly match the number of dynamic descriptors. %s",
7173946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            setCount, total_dynamic_descriptors, dynamicOffsetCount, validation_error_map[VALIDATION_ERROR_00975]);
71745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
71755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7176b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7177946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
71784a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
71794a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                       pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
71805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7182bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7183bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkIndexType indexType) {
7184946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
718556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7186593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that IBs have correct usage state flagged
7187b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7188b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
71899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
71909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
71915cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && buffer_state) {
7192baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBindIndexBuffer()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01357);
7193946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
7194946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindIndexBuffer()", VALIDATION_ERROR_02543);
7195ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        std::function<bool()> function = [=]() {
7196ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindIndexBuffer()");
7197ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        };
7198ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->validate_functions.push_back(function);
7199ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDINDEXBUFFER);
7200ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        VkDeviceSize offset_align = 0;
7201ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        switch (indexType) {
7202ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT16:
7203ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 2;
7204ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
7205ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT32:
7206ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 4;
7207ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
7208ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            default:
7209ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0
7210ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
72115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7212ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        if (!offset_align || (offset % offset_align)) {
7213df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7214df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS",
7215946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") does not fall on alignment (%s) boundary.", offset,
7216946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            string_VkIndexType(indexType));
7217ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
7218ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->status |= CBSTATUS_INDEX_BUFFER_BOUND;
7219ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7220ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
72215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7222b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7223946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
72245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
72265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisvoid updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) {
72275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t end = firstBinding + bindingCount;
72285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->currentDrawData.buffers.size() < end) {
72295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.resize(end);
72305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
72315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bindingCount; ++i) {
72325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i];
72335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
72345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7236e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic inline void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); }
72375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7238bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
7239bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
7240946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
724156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7242593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that VBs have correct usage state flagged
7243b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7244b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
72459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
72469f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    if (cb_node) {
7247baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBindVertexBuffers()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01423);
7248baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffers()");
7249ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t i = 0; i < bindingCount; ++i) {
7250ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            auto buffer_state = GetBufferState(dev_data, pBuffers[i]);
7251ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            assert(buffer_state);
7252946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindVertexBuffers()", VALIDATION_ERROR_02546);
7253ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            std::function<bool()> function = [=]() {
7254ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindVertexBuffers()");
7255ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            };
7256ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cb_node->validate_functions.push_back(function);
72575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7258ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDVERTEXBUFFER);
7259ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        updateResourceTracking(cb_node, firstBinding, bindingCount, pBuffers);
72605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
72617828015969ab31ee01d597f0288cbb124b637fcdMark Lobodzinski        assert(0);
72625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7263b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7264946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
72655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
726725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Expects global_lock to be held by caller
72685569d6457ac22e7d245f3cdee045e71ffbc8b06eTobin Ehlisstatic void MarkStoreImagesAndBuffersAsWritten(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
72697a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto imageView : pCB->updateImages) {
72709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, imageView);
7271cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!view_state) continue;
7272249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
72739a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, view_state->create_info.image);
72741facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        assert(image_state);
7275e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
72761facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, image_state, true);
7277e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
72787a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
72797a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
72807a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    }
72817a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto buffer : pCB->updateBuffers) {
72829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, buffer);
72835cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        assert(buffer_state);
7284e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
72855cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, buffer_state, true);
7286e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
72877a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
72887a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
72895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
72905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7292ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle validation for all CmdDraw* type functions
7293ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool ValidateCmdDrawType(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7294baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                CMD_TYPE cmd_type, GLOBAL_CB_NODE **cb_state, const char *caller, VkQueueFlags queue_flags,
7295baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                UNIQUE_VALIDATION_ERROR_CODE queue_flag_code, UNIQUE_VALIDATION_ERROR_CODE msg_code,
7296baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                UNIQUE_VALIDATION_ERROR_CODE const dynamic_state_msg_code) {
729758b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    bool skip = false;
72989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cb_state = GetCBNode(dev_data, cmd_buffer);
729958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (*cb_state) {
7300baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, *cb_state, caller, queue_flags, queue_flag_code);
7301ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        skip |= ValidateCmd(dev_data, *cb_state, cmd_type, caller);
73024f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        skip |= ValidateDrawState(dev_data, *cb_state, indexed, bind_point, caller, dynamic_state_msg_code);
730325d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        skip |= (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) ? outsideRenderPass(dev_data, *cb_state, caller, msg_code)
730425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis                                                                : insideRenderPass(dev_data, *cb_state, caller, msg_code);
730558b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
730658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    return skip;
730758b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis}
730858b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis
730925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis// Generic function to handle state update for all CmdDraw* and CmdDispatch* type functions
7310ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawDispatchType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7311ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           CMD_TYPE cmd_type) {
7312ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateDrawState(dev_data, cb_state, bind_point);
73132f921d33544c162dcb726fc3c7b915e89c02ff24Tobin Ehlis    MarkStoreImagesAndBuffersAsWritten(dev_data, cb_state);
73141ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis    UpdateCmdBufferLastCmd(cb_state, cmd_type);
731525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
731625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7317ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle state update for all CmdDraw* type functions
7318ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7319b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes                                   CMD_TYPE cmd_type) {
7320ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, cmd_type);
7321c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    updateResourceTrackingOnDraw(cb_state);
7322b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    cb_state->hasDrawCmd = true;
7323ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7324ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7325ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDraw(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7326ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   GLOBAL_CB_NODE **cb_state, const char *caller) {
7327baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAW, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
7328baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                               VALIDATION_ERROR_01364, VALIDATION_ERROR_01365, VALIDATION_ERROR_02203);
7329ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7330ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7331ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDraw(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7332b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAW);
7333c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis}
7334c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis
733589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
733689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                   uint32_t firstVertex, uint32_t firstInstance) {
733756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
733858b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7339b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7340ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = PreCallValidateCmdDraw(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state, "vkCmdDraw()");
7341b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
734258b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (!skip) {
73434a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
7344c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.lock();
7345ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDraw(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7346c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.unlock();
7347c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    }
73485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7350ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexed(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7351ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
7352baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXED, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
7353baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                               VALIDATION_ERROR_01371, VALIDATION_ERROR_01372, VALIDATION_ERROR_02216);
7354ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7355ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7356ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexed(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7357b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXED);
7358ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7359ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7360bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
7361bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
736256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7363ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7364b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7365ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexed(dev_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7366ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              "vkCmdDrawIndexed()");
7367b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7368ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    if (!skip) {
73694a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
7370ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.lock();
7371ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexed(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7372ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.unlock();
7373ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    }
73745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7376ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7377ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
7378ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           const char *caller) {
73794f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDIRECT, cb_state, caller,
7380baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                    VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01380, VALIDATION_ERROR_01381, VALIDATION_ERROR_02234);
73819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
738235ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02544);
738313c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
738413c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // VkDrawIndirectCommand structures accessed by this command must be 0, which will require access to the contents of 'buffer'.
7385d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    return skip;
7386d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7387d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7388ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7389ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          BUFFER_STATE *buffer_state) {
7390b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDIRECT);
7391d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
7392d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7393d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7394bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
7395bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           uint32_t stride) {
739656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7397d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7398d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7399b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7400872a2f0ca3ffdeddfa7483e777191fa64b853892Tony Barbour    bool skip = PreCallValidateCmdDrawIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7401ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               &buffer_state, "vkCmdDrawIndirect()");
7402b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7403d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    if (!skip) {
74044a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
7405d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.lock();
7406ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
7407d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.unlock();
7408d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    }
74095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7411ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexedIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7412ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7413ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  BUFFER_STATE **buffer_state, const char *caller) {
7414ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXEDINDIRECT, cb_state, caller,
7415baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                    VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01392, VALIDATION_ERROR_01393, VALIDATION_ERROR_02272);
74169a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
741735ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02545);
741813c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
741913c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // VkDrawIndexedIndirectCommand structures accessed by this command must be 0, which will require access to the contents of
742013c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // 'buffer'.
74210c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    return skip;
74220c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
74230c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7424ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexedIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7425ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                 BUFFER_STATE *buffer_state) {
7426b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXEDINDIRECT);
74270c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
74280c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
74290c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7430bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7431bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  uint32_t count, uint32_t stride) {
743256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
74330c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
74340c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7435b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
74360c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexedIndirect(dev_data, commandBuffer, buffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS,
7437ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                      &cb_state, &buffer_state, "vkCmdDrawIndexedIndirect()");
7438b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
74390c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    if (!skip) {
74404a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
74410c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.lock();
7442ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexedIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
74430c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.unlock();
74440c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    }
74455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7447ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatch(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7448ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                       VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
7449baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCH, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
7450baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                               VALIDATION_ERROR_01561, VALIDATION_ERROR_01562, VALIDATION_ERROR_UNDEFINED);
745125d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
745225d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7453ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatch(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7454ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCH);
745525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
745625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
745789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
745856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
745925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7460b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7461ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip =
7462ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PreCallValidateCmdDispatch(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_COMPUTE, &cb_state, "vkCmdDispatch()");
7463b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
746425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    if (!skip) {
74654a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatch(commandBuffer, x, y, z);
746625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.lock();
7467ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatch(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
746825d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.unlock();
746925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    }
74705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7472ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatchIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7473ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7474ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               BUFFER_STATE **buffer_state, const char *caller) {
7475baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    bool skip =
7476baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCHINDIRECT, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
7477baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                            VALIDATION_ERROR_01568, VALIDATION_ERROR_01569, VALIDATION_ERROR_UNDEFINED);
74789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
747935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02547);
748079c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    return skip;
748179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
748279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7483ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatchIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7484ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              BUFFER_STATE *buffer_state) {
7485ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCHINDIRECT);
748679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
748779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
748879c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7489bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
749056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
749179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
749279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7493b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
74947433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis    bool skip = PreCallValidateCmdDispatchIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_COMPUTE,
7495ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                   &cb_state, &buffer_state, "vkCmdDispatchIndirect()");
7496b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
749779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    if (!skip) {
74984a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatchIndirect(commandBuffer, buffer, offset);
749979c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.lock();
7500ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatchIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, buffer_state);
750179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.unlock();
750279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    }
75035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
750589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
750689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                         uint32_t regionCount, const VkBufferCopy *pRegions) {
7507c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7508b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7509ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
7510c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7511c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
7512c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
7513593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7514c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    if (cb_node && src_buffer_state && dst_buffer_state) {
7515c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        bool skip = PreCallValidateCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7516c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        if (!skip) {
7517c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            PreCallRecordCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7518c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            lock.unlock();
7519c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            device_data->dispatch_table.CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
7520c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        }
7521ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7522c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        lock.unlock();
7523ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
75245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
75255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7527bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7528bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7529bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageCopy *pRegions) {
75306a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    bool skip = false;
75316a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7532b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7533249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
75346a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
75356a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
75366a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
75371facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && src_image_state && dst_image_state) {
75386a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        skip = PreCallValidateCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions,
75396a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                           srcImageLayout, dstImageLayout);
75406a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        if (!skip) {
7541a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis            PreCallRecordCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, srcImageLayout,
7542a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                      dstImageLayout);
75436a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            lock.unlock();
75446a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            device_data->dispatch_table.CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
75456a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                                     pRegions);
75465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7547249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
75486a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        lock.unlock();
7549249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
75505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
75515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7553eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski// Validate that an image's sampleCount matches the requirement for a specific API call
755460568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageSampleCount(layer_data *dev_data, IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count,
755560568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinski                              const char *location, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
7556eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    bool skip = false;
75571facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state->createInfo.samples != sample_count) {
755855eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen        skip =
755955eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
756055eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    reinterpret_cast<uint64_t &>(image_state->image), 0, msgCode, "DS",
756155eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    "%s for image 0x%" PRIxLEAST64 " was created with a sample count of %s but must be %s. %s", location,
756255eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    reinterpret_cast<uint64_t &>(image_state->image), string_VkSampleCountFlagBits(image_state->createInfo.samples),
756355eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    string_VkSampleCountFlagBits(sample_count), validation_error_map[msgCode]);
7564eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    }
7565eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    return skip;
7566eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski}
7567eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski
7568bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7569bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7570bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageBlit *pRegions, VkFilter filter) {
757156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7572b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7573593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
75749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
75759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
75769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
75770dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7578055112ec99304db71d55b69a60e1da14e8af8f60Mark Lobodzinski    bool skip = PreCallValidateCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, filter);
75790dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7580dca02371c9531e7a9a2a51decae1db4d297862c4Mark Lobodzinski    if (!skip) {
7581eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        PreCallRecordCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state);
7582eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        lock.unlock();
75834a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
75844a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                              pRegions, filter);
75850dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski    }
75865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7588bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
7589bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkImageLayout dstImageLayout, uint32_t regionCount,
7590bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBufferImageCopy *pRegions) {
7591940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7592b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7593940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
7594940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7595940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
7596940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
7597940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_buffer_state && dst_image_state) {
7598940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyBufferToImage(device_data, dstImageLayout, cb_node, src_buffer_state, dst_image_state,
759971c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyBufferToImage()");
7600ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7601d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7602ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
7603e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01244 here, or put in object tracker?
76045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7605940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
7606a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis        PreCallRecordCmdCopyBufferToImage(device_data, cb_node, src_buffer_state, dst_image_state, regionCount, pRegions,
7607a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                          dstImageLayout);
7608d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7609940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
7610d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
76115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7613bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7614bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
7615940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
7616940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7617b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7618593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7619940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7620940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
7621940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
7622940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_image_state && dst_buffer_state) {
7623940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyImageToBuffer(device_data, srcImageLayout, cb_node, src_image_state, dst_buffer_state,
762471c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyImageToBuffer()");
7625ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7626d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7627ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
7628e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01262 here, or put in object tracker?
76295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7630940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
7631a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis        PreCallRecordCmdCopyImageToBuffer(device_data, cb_node, src_image_state, dst_buffer_state, regionCount, pRegions,
7632a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                          srcImageLayout);
7633d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7634940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
7635d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
76365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7638bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7639bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkDeviceSize dataSize, const uint32_t *pData) {
76403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
764156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7642b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7643593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
76449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
76459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
76465cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
76473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdUpdateBuffer()", VALIDATION_ERROR_02530);
7648ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
76495cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
7650ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
76513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, VALIDATION_ERROR_01146,
76523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                         "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
7653e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
76545cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
7655e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
76565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
76579f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
7658593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
76593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdUpdateBuffer()",
76603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                      VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_01154);
76613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()");
76621ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_node, CMD_UPDATEBUFFER);
76633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= insideRenderPass(dev_data, cb_node, "vkCmdUpdateBuffer()", VALIDATION_ERROR_01155);
7664ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7665ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
76665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7667b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
76683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
76695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7671bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7672bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         VkDeviceSize size, uint32_t data) {
767323bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7674b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
767523bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
767623bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto buffer_state = GetBufferState(device_data, dstBuffer);
7677593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
767823bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    if (cb_node && buffer_state) {
767923bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        bool skip = PreCallValidateCmdFillBuffer(device_data, cb_node, buffer_state);
768023bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        if (!skip) {
768123bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            PreCallRecordCmdFillBuffer(device_data, cb_node, buffer_state);
768223bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            lock.unlock();
768323bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            device_data->dispatch_table.CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
768423bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        }
7685ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
768623bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        lock.unlock();
7687ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
76885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
76895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
76914028af23e688ab5730f48ab2244dd042e2eefaedMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
76924028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearAttachment *pAttachments, uint32_t rectCount,
76934028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearRect *pRects) {
76944028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    bool skip = false;
769556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
76964028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    {
76974028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
76984028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        skip = PreCallValidateCmdClearAttachments(dev_data, commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
76994028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    }
7700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
77015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
77030482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
77040482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkClearColorValue *pColor, uint32_t rangeCount,
77050482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkImageSubresourceRange *pRanges) {
770656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7707b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
77080482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
77090482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearColorImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
77100482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
77110482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARCOLORIMAGE);
77120482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
77130482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
77140482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    }
77150482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski}
77160482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
77170482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
77180482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
77190482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkImageSubresourceRange *pRanges) {
772056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
77210482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
77220482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
77230482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearDepthStencilImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
77240482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
77250482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARDEPTHSTENCILIMAGE);
77260482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
77270482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
77287f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    }
77295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7731bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7732bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7733bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkImageResolve *pRegions) {
773456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7735b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7736593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
77379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
77389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
77399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
774009fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
774125f7873c9ce3ed39d18bba8750d7538905e150dfMark Lobodzinski    bool skip = PreCallValidateCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions);
774209fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
774309fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    if (!skip) {
77446c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        PreCallRecordCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state);
77456c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        lock.unlock();
77464a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
77474a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                 pRegions);
774809fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    }
77495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7751a8d1e377bdeaf61a3209cb997502da4356a185bbMike WeiblenVKAPI_ATTR void VKAPI_CALL GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
7752a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen                                                     VkSubresourceLayout *pLayout) {
7753a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
7754a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen
7755a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    bool skip = PreCallValidateGetImageSubresourceLayout(device_data, image, pSubresource);
7756a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    if (!skip) {
7757b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        device_data->dispatch_table.GetImageSubresourceLayout(device, image, pSubresource, pLayout);
7758b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    }
7759b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski}
7760b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski
7761b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentinebool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
776256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
77639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
7764b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (pCB) {
7765b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventToStageMap[event] = stageMask;
7766b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7767b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    auto queue_data = dev_data->queueMap.find(queue);
7768b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (queue_data != dev_data->queueMap.end()) {
7769b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        queue_data->second.eventToStageMap[event] = stageMask;
7770b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7771b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return false;
7772b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
7773b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
7774bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
77753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
777656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7777b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
77789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
77795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
77803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
77813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                      VALIDATION_ERROR_00237);
77823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()");
77831ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETEVENT);
77843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent()", VALIDATION_ERROR_00238);
77853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
7786208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdSetEvent()", VALIDATION_ERROR_00230, VALIDATION_ERROR_00231);
77879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
77884710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
77894710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            addCommandBufferBinding(&event_state->cb_bindings,
77907a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                    {reinterpret_cast<uint64_t &>(event), kVulkanObjectTypeEvent}, pCB);
77914710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
7792ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
77935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
7794c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
7795c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
7796c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
7797b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
7798b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, stageMask);
7799b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
78005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7801b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
78023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetEvent(commandBuffer, event, stageMask);
78035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7805bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
78063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
780756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7808b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
78099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
78105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
78113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdResetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
78123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                      VALIDATION_ERROR_00248);
78133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()");
78141ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_RESETEVENT);
78153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent()", VALIDATION_ERROR_00249);
78163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
7817208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdResetEvent()", VALIDATION_ERROR_00240, VALIDATION_ERROR_00241);
78189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
78194710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
78204710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            addCommandBufferBinding(&event_state->cb_bindings,
78217a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                    {reinterpret_cast<uint64_t &>(event), kVulkanObjectTypeEvent}, pCB);
78224710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
7823ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
78245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
7825c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
7826c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
7827c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
7828208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        // TODO : Add check for VALIDATION_ERROR_00226
7829b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
7830b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, VkPipelineStageFlags(0));
7831b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
78325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7833b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
78343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdResetEvent(commandBuffer, event, stageMask);
78355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7837e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
7838e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
7839e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
7840e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkImageMemoryBarrier *pImageMemBarriers) {
7841a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    bool skip = false;
784256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(cmdBuffer), layer_data_map);
78439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, cmdBuffer);
78445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass && memBarrierCount) {
7845ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        if (!pCB->activeRenderPass->hasSelfDependency[pCB->activeSubpass]) {
7846df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7847df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7848cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Barriers cannot be set during subpass %d "
7849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "with no self dependency specified.",
7850a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, pCB->activeSubpass);
78515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
78525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
78535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
78545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pImageMemBarriers[i];
78559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_data = GetImageState(dev_data, mem_barrier->image);
78566d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        if (image_data) {
78575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex;
78585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex;
78596d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (image_data->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
78605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // srcQueueFamilyIndex and dstQueueFamilyIndex must both
78615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // be VK_QUEUE_FAMILY_IGNORED
78625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) {
7863df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7864df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(cmdBuffer), __LINE__,
7865df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
7866df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "%s: Image Barrier for image 0x%" PRIx64
7867df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    " was created with sharingMode of "
7868df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "VK_SHARING_MODE_CONCURRENT. Src and dst "
7869df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.",
7870df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
78715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
78725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
78735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and
78745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED,
78755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // or both be a valid queue family
78765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) &&
78775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (src_q_f_index != dst_q_f_index)) {
7878df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7879df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(cmdBuffer), __LINE__,
7880df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
7881df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "%s: Image 0x%" PRIx64
7882df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    " was created with sharingMode "
7883df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or "
7884df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both "
7885df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "must be.",
7886df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
78875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) &&
7888b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                           ((src_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
7889b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                            (dst_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()))) {
7890df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7891df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(cmdBuffer), __LINE__,
7892df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
7893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "%s: Image 0x%" PRIx64
7894cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    " was created with sharingMode "
7895a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d"
7896a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER
7897a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    "queueFamilies crated for this device.",
7898a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image), src_q_f_index, dst_q_f_index,
7899a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    dev_data->phys_dev_properties.queue_family_properties.size());
79005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
79015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
79025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
79035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
79045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (mem_barrier) {
7905d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            if (mem_barrier->oldLayout != mem_barrier->newLayout) {
7906a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |=
7907d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour                    ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source");
7908a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |=
7909d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour                    ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest");
7910d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            }
79115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
7912df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip |=
7913df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7914df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7915df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Image Layout cannot be transitioned to UNDEFINED or "
7916df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "PREINITIALIZED.",
7917df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            funcName);
79185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
79191d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill            VkFormat format = VK_FORMAT_UNDEFINED;
79201d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill            uint32_t arrayLayers = 0, mipLevels = 0;
79215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            bool imageFound = false;
79226d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (image_data) {
79236d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                format = image_data->createInfo.format;
79246d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                arrayLayers = image_data->createInfo.arrayLayers;
79256d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                mipLevels = image_data->createInfo.mipLevels;
79265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                imageFound = true;
7927599899dabe438a8ea144c0add628d3f5afe54dd0Chris Forbes            } else if (dev_data->device_extensions.khr_swapchain_enabled) {
79289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto imageswap_data = GetSwapchainFromImage(dev_data, mem_barrier->image);
7929170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis                if (imageswap_data) {
79309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto swapchain_data = GetSwapchainNode(dev_data, imageswap_data);
7931b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                    if (swapchain_data) {
7932b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                        format = swapchain_data->createInfo.imageFormat;
7933b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                        arrayLayers = swapchain_data->createInfo.imageArrayLayers;
79345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        mipLevels = 1;
79355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        imageFound = true;
79365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
79375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
79385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
79395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (imageFound) {
7940e08b485346524a30ddfe6526f7dcbbf78c776d10Mark Lobodzinski                skip |= ValidateImageSubrangeLevelLayerCounts(dev_data, mem_barrier->subresourceRange, funcName);
7941c37c65e9ff3a0abc86e706ee61d21e1dec882731Tobin Ehlis                auto aspect_mask = mem_barrier->subresourceRange.aspectMask;
7942a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= ValidateImageAspectMask(dev_data, image_data->image, format, aspect_mask, funcName);
794395b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski
794495b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                uint32_t layer_count = ResolveRemainingLayers(&mem_barrier->subresourceRange, image_data->createInfo.arrayLayers);
794595b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                if ((mem_barrier->subresourceRange.baseArrayLayer + layer_count) > arrayLayers) {
7946df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
794795b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(cmdBuffer), __LINE__,
794895b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                                    DRAWSTATE_INVALID_BARRIER, "DS",
794995b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                                    "%s: Subresource must have the sum of the baseArrayLayer (%d) and layerCount (%d) be less "
7950cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "than or equal to the total number of layers (%d).",
795195b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                                    funcName, mem_barrier->subresourceRange.baseArrayLayer, layer_count, arrayLayers);
79525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
795395b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski
795495b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                uint32_t level_count = ResolveRemainingLevels(&mem_barrier->subresourceRange, image_data->createInfo.mipLevels);
795595b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                if ((mem_barrier->subresourceRange.baseMipLevel + level_count) > mipLevels) {
7956df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip |= log_msg(
7957df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7958df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
795995b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                        "%s: Subresource must have the sum of the baseMipLevel (%d) and levelCount (%d) be less than or equal to "
7960df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "the total number of levels (%d).",
796195b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                        funcName, mem_barrier->subresourceRange.baseMipLevel, level_count, mipLevels);
79625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
79635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
79645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
79655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
79665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
79675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pBufferMemBarriers[i];
79685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->activeRenderPass) {
7969df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7970df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7971df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Buffer Barriers cannot be used during a render pass.", funcName);
79725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7973cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!mem_barrier) continue;
79745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
79755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate buffer barrier queue family indices
79765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
7977b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->srcQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
79785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
7979b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->dstQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size())) {
7980df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7981df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
7982cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64
7983cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            " has QueueFamilyIndex greater "
7984a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.",
7985a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
7986a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            dev_data->phys_dev_properties.queue_family_properties.size());
79875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
79885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
79899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, mem_barrier->buffer);
79905cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        if (buffer_state) {
79915cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            auto buffer_size = buffer_state->requirements.size;
79925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->offset >= buffer_size) {
7993a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= log_msg(
7994df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7995df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7996df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " which is not less than total size 0x%" PRIx64 ".",
799794c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
7998df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    reinterpret_cast<const uint64_t &>(mem_barrier->offset), reinterpret_cast<const uint64_t &>(buffer_size));
7999df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
8000df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip |=
8001df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8002df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
8003df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " and size 0x%" PRIx64
8004df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            " whose sum is greater than total size 0x%" PRIx64 ".",
8005df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
8006df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(mem_barrier->offset),
8007df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(mem_barrier->size), reinterpret_cast<const uint64_t &>(buffer_size));
80085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
80095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
80105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8011a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    return skip;
80125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8014bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool validateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex,
8015bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            VkPipelineStageFlags sourceStageMask) {
80163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
8017b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    VkPipelineStageFlags stageMask = 0;
801856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
8019b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    for (uint32_t i = 0; i < eventCount; ++i) {
80202ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event = pCB->events[firstEventIndex + i];
8021b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        auto queue_data = dev_data->queueMap.find(queue);
8022cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (queue_data == dev_data->queueMap.end()) return false;
80232ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event_data = queue_data->second.eventToStageMap.find(event);
8024b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        if (event_data != queue_data->second.eventToStageMap.end()) {
8025b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            stageMask |= event_data->second;
8026b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        } else {
80279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto global_event_data = GetEventNode(dev_data, event);
80289556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis            if (!global_event_data) {
80293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
80303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
80313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "Event 0x%" PRIx64 " cannot be waited on if it has never been set.",
80323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                reinterpret_cast<const uint64_t &>(event));
8033b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            } else {
80349556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis                stageMask |= global_event_data->stageMask;
8035b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            }
8036b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        }
8037b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
8038c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // TODO: Need to validate that host_bit is only set if set event is called
8039c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // but set event can be called at any time.
8040c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    if (sourceStageMask != stageMask && sourceStageMask != (stageMask | VK_PIPELINE_STAGE_HOST_BIT)) {
80413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
80423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_00254, "DS",
80433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Submitting cmdbuffer with call to VkCmdWaitEvents "
80443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "using srcStageMask 0x%X which must be the bitwise "
80453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "OR of the stageMask parameters used in calls to "
80463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if "
80473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "used with vkSetEvent but instead is 0x%X. %s",
80483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        sourceStageMask, stageMask, validation_error_map[VALIDATION_ERROR_00254]);
8049b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
80503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
8051b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
8052b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
805307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski// Note that we only check bits that HAVE required queueflags -- don't care entries are skipped
805407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic std::unordered_map<VkPipelineStageFlags, VkQueueFlags> supported_pipeline_stages_table = {
805507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
805607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
805707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
805807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
805907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
806007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
806107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
806207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
806307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
806407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
806507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
806607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_QUEUE_COMPUTE_BIT},
806707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT},
806807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_QUEUE_GRAPHICS_BIT}};
806907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
807007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic const VkPipelineStageFlags stage_flag_bit_array[] = {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX,
807107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
807207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
807307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
807407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
807507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
807607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
807707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
807807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
807907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
808007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
808107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
808207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TRANSFER_BIT,
808307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT};
808407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
808507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool CheckStageMaskQueueCompatibility(layer_data *dev_data, VkCommandBuffer command_buffer, VkPipelineStageFlags stage_mask,
808607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      VkQueueFlags queue_flags, const char *function, const char *src_or_dest,
808707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      UNIQUE_VALIDATION_ERROR_CODE error_code) {
808807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
808907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Lookup each bit in the stagemask and check for overlap between its table bits and queue_flags
809007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    for (const auto &item : stage_flag_bit_array) {
809107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if (stage_mask & item) {
809207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            if ((supported_pipeline_stages_table[item] & queue_flags) == 0) {
809307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                skip |=
809407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
809507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            reinterpret_cast<uint64_t &>(command_buffer), __LINE__, error_code, "DL",
809607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "%s(): %s flag %s is not compatible with the queue family properties of this "
809707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "command buffer. %s",
809807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            function, src_or_dest, string_VkPipelineStageFlagBits(static_cast<VkPipelineStageFlagBits>(item)),
809907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            validation_error_map[error_code]);
810007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            }
810107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
810207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
810307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
810407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
810507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
810607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool ValidateStageMasksAgainstQueueCapabilities(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
810707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                VkPipelineStageFlags source_stage_mask, VkPipelineStageFlags dest_stage_mask,
810807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                const char *function, UNIQUE_VALIDATION_ERROR_CODE error_code) {
810907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
811007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    uint32_t queue_family_index = dev_data->commandPoolMap[cb_state->createInfo.commandPool].queueFamilyIndex;
811156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(dev_data->physical_device), instance_layer_data_map);
81129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, dev_data->physical_device);
811307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
811407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Any pipeline stage included in srcStageMask or dstStageMask must be supported by the capabilities of the queue family
811507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // specified by the queueFamilyIndex member of the VkCommandPoolCreateInfo structure that was used to create the VkCommandPool
811607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // that commandBuffer was allocated from, as specified in the table of supported pipeline stages.
811707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
811807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    if (queue_family_index < physical_device_state->queue_family_properties.size()) {
811907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        VkQueueFlags specified_queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
812007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
812107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((source_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
812207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, source_stage_mask, specified_queue_flags,
812307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "srcStageMask", error_code);
812407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
812507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((dest_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
812607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, dest_stage_mask, specified_queue_flags,
812707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "dstStageMask", error_code);
812807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
812907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
813007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
813107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
813207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
8133d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
8134d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
8135d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8136d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8137d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
8138d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
813956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8140b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
81419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8142d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
8143d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= ValidateStageMasksAgainstQueueCapabilities(dev_data, cb_state, sourceStageMask, dstStageMask, "vkCmdWaitEvents",
8144d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                                           VALIDATION_ERROR_02510);
8145208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, sourceStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_02067,
8146208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_02069);
8147208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, dstStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_02068,
8148208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_02070);
8149d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        auto first_event_index = cb_state->events.size();
81505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < eventCount; ++i) {
81519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto event_state = GetEventNode(dev_data, pEvents[i]);
81524710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            if (event_state) {
81534710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis                addCommandBufferBinding(&event_state->cb_bindings,
81547a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                        {reinterpret_cast<const uint64_t &>(pEvents[i]), kVulkanObjectTypeEvent},
8155d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                        cb_state);
8156d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                event_state->cb_bindings.insert(cb_state);
8157ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis            }
8158d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->waitedEvents.insert(pEvents[i]);
8159d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->events.push_back(pEvents[i]);
81605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8161d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        std::function<bool(VkQueue)> event_update =
8162d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            std::bind(validateEventStageMask, std::placeholders::_1, cb_state, eventCount, first_event_index, sourceStageMask);
8163d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        cb_state->eventUpdates.push_back(event_update);
8164baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWaitEvents()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8165baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_00262);
8166ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WAITEVENTS, "vkCmdWaitEvents()");
8167ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WAITEVENTS);
8168a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen        skip |=
8169a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen            ValidateBarriersToImages(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers, "vkCmdWaitEvents()");
8170e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        if (!skip) {
8171e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski            TransitionImageLayouts(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
8172e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        }
8173e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski
8174364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= ValidateBarriers("vkCmdWaitEvents()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
8175d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
81765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8177b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8178d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (!skip)
81794a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
81804a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
81814a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               imageMemoryBarrierCount, pImageMemoryBarriers);
81825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
818403122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinskistatic bool PreCallValidateCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
818503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
818603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
818703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
818803122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
818903122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    bool skip = false;
819003122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMasksAgainstQueueCapabilities(device_data, cb_state, srcStageMask, dstStageMask, "vkCmdPipelineBarrier",
819103122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                       VALIDATION_ERROR_02513);
8192baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    skip |= ValidateCmdQueueFlags(device_data, cb_state, "vkCmdPipelineBarrier()",
8193baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_00280);
819403122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateCmd(device_data, cb_state, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()");
819503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMaskGsTsEnables(device_data, srcStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_00265,
819603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                         VALIDATION_ERROR_00267);
819703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMaskGsTsEnables(device_data, dstStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_00266,
819803122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                         VALIDATION_ERROR_00268);
8199a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen    skip |= ValidateBarriersToImages(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers,
8200a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen                                     "vkCmdPipelineBarrier()");
820103122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateBarriers("vkCmdPipelineBarrier()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
820203122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                             pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
820303122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    return skip;
820403122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski}
820503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski
82066f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinskistatic void PreCallRecordCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
82076f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski                                            uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
82086f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    UpdateCmdBufferLastCmd(cb_state, CMD_PIPELINEBARRIER);
82096f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    TransitionImageLayouts(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
82106f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski}
82116f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski
8212d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
8213d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
8214d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8215d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8216d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
8217d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
82186f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8219b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
82206f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(device_data, commandBuffer);
8221d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
82226f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        skip |= PreCallValidateCmdPipelineBarrier(device_data, cb_state, commandBuffer, srcStageMask, dstStageMask,
822303122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
822403122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
82256f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        if (!skip) {
82266f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski            PreCallRecordCmdPipelineBarrier(device_data, cb_state, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
82276f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        }
82286f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    } else {
82296f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        assert(0);
82305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8231b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8232a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour    if (!skip) {
8233a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour        device_data->dispatch_table.CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount,
8234a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour                                                       pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
8235a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour                                                       imageMemoryBarrierCount, pImageMemoryBarriers);
8236a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour    }
82375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
82385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8239d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool setQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value) {
824056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
82419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
8242d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (pCB) {
8243d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryToStateMap[object] = value;
8244d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8245d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8246d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (queue_data != dev_data->queueMap.end()) {
8247d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        queue_data->second.queryToStateMap[object] = value;
8248d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8249d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return false;
8250d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8251d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8252bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
82533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
825456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8255b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
82569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
82575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
82585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
82595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.insert(query);
82605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!pCB->startedQueries.count(query)) {
82615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->startedQueries.insert(query);
82625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
82633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdBeginQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
82643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                      VALIDATION_ERROR_01039);
82653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
82661ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_BEGINQUERY);
82679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
82687a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                {reinterpret_cast<uint64_t &>(queryPool), kVulkanObjectTypeQueryPool}, pCB);
82695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8270b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
82713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBeginQuery(commandBuffer, queryPool, slot, flags);
82725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
82735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
827489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
8275946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
827656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8277b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8278946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8279946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
82805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
8281946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (!cb_state->activeQueries.count(query)) {
8282df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8283df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_01041, "DS",
8284df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "Ending a query before it was started: queryPool 0x%" PRIx64 ", index %d. %s", (uint64_t)(queryPool),
8285df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            slot, validation_error_map[VALIDATION_ERROR_01041]);
82865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
8287946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->activeQueries.erase(query);
82885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8289946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8290946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_state->queryUpdates.push_back(query_update);
8291baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdEndQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8292baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_01046);
8293946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_ENDQUERY, "VkCmdEndQuery()");
8294946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_ENDQUERY);
82959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
82967a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                {reinterpret_cast<uint64_t &>(queryPool), kVulkanObjectTypeQueryPool}, cb_state);
82975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8298b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8299946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdEndQuery(commandBuffer, queryPool, slot);
83005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
83015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8302bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8303bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint32_t queryCount) {
8304946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
830556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8306b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8307946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8308946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
83095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < queryCount; i++) {
83105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            QueryObject query = {queryPool, firstQuery + i};
8311946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->waitedEventsBeforeQueryReset[query] = cb_state->waitedEvents;
8312946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            std::function<bool(VkQueue)> query_update =
8313946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, false);
8314946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->queryUpdates.push_back(query_update);
8315946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        }
8316baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdResetQueryPool()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8317baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_01024);
8318946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
8319946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_RESETQUERYPOOL);
8320946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= insideRenderPass(dev_data, cb_state, "vkCmdResetQueryPool()", VALIDATION_ERROR_01025);
83219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
83227a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                {reinterpret_cast<uint64_t &>(queryPool), kVulkanObjectTypeQueryPool}, cb_state);
83235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8324b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8325946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
83265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
83275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8328d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool validateQuery(VkQueue queue, GLOBAL_CB_NODE *pCB, VkQueryPool queryPool, uint32_t queryCount, uint32_t firstQuery) {
83293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
833056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
8331d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8332cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (queue_data == dev_data->queueMap.end()) return false;
8333d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    for (uint32_t i = 0; i < queryCount; i++) {
8334d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        QueryObject query = {queryPool, firstQuery + i};
8335d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        auto query_data = queue_data->second.queryToStateMap.find(query);
8336d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        bool fail = false;
8337d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (query_data != queue_data->second.queryToStateMap.end()) {
8338d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (!query_data->second) {
8339d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8340d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8341d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        } else {
8342d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            auto global_query_data = dev_data->queryToStateMap.find(query);
8343d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (global_query_data != dev_data->queryToStateMap.end()) {
8344d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                if (!global_query_data->second) {
8345d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                    fail = true;
8346d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
8347d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            } else {
8348d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8349d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8350d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8351d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (fail) {
83523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
83533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
83543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Requesting a copy from query to buffer with invalid query: queryPool 0x%" PRIx64 ", index %d",
83553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(queryPool), firstQuery + i);
8356d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8357d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
83583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
8359d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8360d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8361bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8362bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
8363bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDeviceSize stride, VkQueryResultFlags flags) {
8364946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
836556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8366b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8367ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
83689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
83699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
83705cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
8371946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_02526);
8372ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
83735cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
8374ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
8375946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, VALIDATION_ERROR_01066,
8376946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                         "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8377e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
83785cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
8379e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
83805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
83819f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8382946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update =
8383ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis            std::bind(validateQuery, std::placeholders::_1, cb_node, queryPool, queryCount, firstQuery);
8384946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_node->queryUpdates.push_back(query_update);
8385baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdCopyQueryPoolResults()",
8386baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_01073);
8387946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
8388ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_COPYQUERYPOOLRESULTS);
8389946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= insideRenderPass(dev_data, cb_node, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_01074);
83909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
83917a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                {reinterpret_cast<uint64_t &>(queryPool), kVulkanObjectTypeQueryPool}, cb_node);
8392ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
8393ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
83945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8395b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8396946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
83974a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset,
83984a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                         stride, flags);
83995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8401bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags,
8402bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                            uint32_t offset, uint32_t size, const void *pValues) {
8403946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
840456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8405b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8406946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8407946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
8408baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdPushConstants()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8409baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_00999);
8410946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
8411946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_PUSHCONSTANTS);
84125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8413946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    skip |= validatePushConstantRange(dev_data, offset, size, "vkCmdPushConstants()");
84149e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if (0 == stageFlags) {
8415df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8416df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00996, "DS",
8417df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "vkCmdPushConstants() call has no stageFlags set. %s", validation_error_map[VALIDATION_ERROR_00996]);
84189e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
84199e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz
8420bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // Check if specified push constant range falls within a pipeline-defined range which has matching stageFlags.
8421bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // The spec doesn't seem to disallow having multiple push constant ranges with the
8422bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // same offset and size, but different stageFlags.  So we can't just check the
8423bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // stageFlags in the first range with matching offset and size.
8424bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    if (!skip) {
8425bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        const auto &ranges = getPipelineLayout(dev_data, layout)->push_constant_ranges;
8426bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        bool found_matching_range = false;
8427bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        for (const auto &range : ranges) {
8428bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz            if ((stageFlags == range.stageFlags) && (offset >= range.offset) && (offset + size <= range.offset + range.size)) {
8429bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz                found_matching_range = true;
843015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                break;
8431a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz            }
84329e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
8433bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        if (!found_matching_range) {
8434df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8435df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00988, "DS",
8436df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "vkCmdPushConstants() stageFlags = 0x%" PRIx32
8437df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            " do not match the stageFlags in any of the ranges with"
8438df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            " offset = %d and size = %d in pipeline layout 0x%" PRIx64 ". %s",
8439bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz                            (uint32_t)stageFlags, offset, size, (uint64_t)layout, validation_error_map[VALIDATION_ERROR_00988]);
844015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        }
84415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8442b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8443946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
84445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8446bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
8447bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             VkQueryPool queryPool, uint32_t slot) {
8448946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
844956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8450b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8451946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8452946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
84535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
8454946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8455946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_state->queryUpdates.push_back(query_update);
8456baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWriteTimestamp()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8457baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_01082);
8458946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
8459946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WRITETIMESTAMP);
84605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8461b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8462946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
84635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
84656600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinskistatic bool MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference *attachments,
84669bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       const VkFramebufferCreateInfo *fbci, VkImageUsageFlagBits usage_flag,
84679bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
8468946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
84696600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
84706600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    for (uint32_t attach = 0; attach < count; attach++) {
84716600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        if (attachments[attach].attachment != VK_ATTACHMENT_UNUSED) {
84726600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Attachment counts are verified elsewhere, but prevent an invalid access
84736600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (attachments[attach].attachment < fbci->attachmentCount) {
84746600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                const VkImageView *image_view = &fbci->pAttachments[attachments[attach].attachment];
84759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, *image_view);
847679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (view_state) {
84779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    const VkImageCreateInfo *ici = &GetImageState(dev_data, view_state->create_info.image)->createInfo;
84786600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    if (ici != nullptr) {
84796600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        if ((ici->usage & usage_flag) == 0) {
8480df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
8481df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                            VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, error_code, "DS",
8482946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "vkCreateFramebuffer:  Framebuffer Attachment (%d) conflicts with the image's "
8483946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "IMAGE_USAGE flags (%s). %s",
8484946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            attachments[attach].attachment, string_VkImageUsageFlagBits(usage_flag),
8485946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            validation_error_map[error_code]);
84866600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        }
84876600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    }
84886600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                }
84896600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
84906600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
84916600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
8492946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    return skip;
84936600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
84946600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
8495d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// Validate VkFramebufferCreateInfo which includes:
8496d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// 1. attachmentCount equals renderPass attachmentCount
84975ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 2. corresponding framebuffer and renderpass attachments have matching formats
84985ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 3. corresponding framebuffer and renderpass attachments have matching sample counts
84995ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 4. fb attachments only have a single mip level
85005ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 5. fb attachment dimensions are each at least as large as the fb
85015ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 6. fb attachments use idenity swizzle
85025ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 7. fb attachments used by renderPass for color/input/ds have correct usage bit set
85036fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis// 8. fb dimensions are within physical device limits
8504d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlisstatic bool ValidateFramebufferCreateInfo(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
85053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
85066600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
85079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto rp_state = GetRenderPassState(dev_data, pCreateInfo->renderPass);
8508127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    if (rp_state) {
8509127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        const VkRenderPassCreateInfo *rpci = rp_state->createInfo.ptr();
8510d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        if (rpci->attachmentCount != pCreateInfo->attachmentCount) {
85113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(
8512d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
85139bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00404, "DS",
8514d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachmentCount of %u does not match attachmentCount of %u of "
85159bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "renderPass (0x%" PRIxLEAST64 ") being used to create Framebuffer. %s",
85169bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                pCreateInfo->attachmentCount, rpci->attachmentCount, reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass),
85179bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                validation_error_map[VALIDATION_ERROR_00404]);
85185ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        } else {
851941ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis            // attachmentCounts match, so make sure corresponding attachment details line up
85205ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            const VkImageView *image_views = pCreateInfo->pAttachments;
85215ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
85229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, image_views[i]);
852312d5600c2f9e32343016fd944432ba95df370797Tobin Ehlis                auto &ivci = view_state->create_info;
852479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.format != rpci->pAttachments[i].format) {
85253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
85265ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
85279bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00408, "DS",
85289bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has format of %s that does not match "
85299bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the format of "
85309bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
853179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkFormat(ivci.format), string_VkFormat(rpci->pAttachments[i].format),
85329bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_00408]);
85335ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
85349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                const VkImageCreateInfo *ici = &GetImageState(dev_data, ivci.image)->createInfo;
85355ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                if (ici->samples != rpci->pAttachments[i].samples) {
85363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
853741ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
85389bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00409, "DS",
85399bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has %s samples that do not match "
85409bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the %s samples used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
854141ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        i, string_VkSampleCountFlagBits(ici->samples), string_VkSampleCountFlagBits(rpci->pAttachments[i].samples),
85429bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_00409]);
85435ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
85445ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                // Verify that view only has a single mip level
854579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.subresourceRange.levelCount != 1) {
85463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
85473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    0, __LINE__, VALIDATION_ERROR_00411, "DS",
85483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has mip levelCount of %u "
85493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "but only a single mip level (levelCount ==  1) is allowed when creating a Framebuffer. %s",
85503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    i, ivci.subresourceRange.levelCount, validation_error_map[VALIDATION_ERROR_00411]);
85515ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
855279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                const uint32_t mip_level = ivci.subresourceRange.baseMipLevel;
8553aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_width = max(1u, ici->extent.width >> mip_level);
8554aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_height = max(1u, ici->extent.height >> mip_level);
855579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if ((ivci.subresourceRange.layerCount < pCreateInfo->layers) || (mip_width < pCreateInfo->width) ||
8556aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    (mip_height < pCreateInfo->height)) {
85572c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                    skip |= log_msg(
85582c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
85592c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        VALIDATION_ERROR_00410, "DS",
85602c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has dimensions smaller "
85612c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "than the corresponding framebuffer dimensions. Here are the respective dimensions for attachment #%u, "
85622c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "framebuffer:\n"
85632c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "width: %u, %u\n"
85642c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "height: %u, %u\n"
85652c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "layerCount: %u, %u\n%s",
85662c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        i, ivci.subresourceRange.baseMipLevel, i, mip_width, pCreateInfo->width, mip_height, pCreateInfo->height,
85672c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        ivci.subresourceRange.layerCount, pCreateInfo->layers, validation_error_map[VALIDATION_ERROR_00410]);
85685ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
856979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (((ivci.components.r != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.r != VK_COMPONENT_SWIZZLE_R)) ||
857079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.g != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.g != VK_COMPONENT_SWIZZLE_G)) ||
857179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.b != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.b != VK_COMPONENT_SWIZZLE_B)) ||
857279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.a != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.a != VK_COMPONENT_SWIZZLE_A))) {
85733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
85745b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
85759bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        VALIDATION_ERROR_00412, "DS",
8576da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has non-identy swizzle. All framebuffer "
8577da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "attachments must have been created with the identity swizzle. Here are the actual swizzle values:\n"
8578da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "r swizzle = %s\n"
8579da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "g swizzle = %s\n"
8580da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "b swizzle = %s\n"
85819bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "a swizzle = %s\n"
85829bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s",
858379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkComponentSwizzle(ivci.components.r), string_VkComponentSwizzle(ivci.components.g),
85849bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        string_VkComponentSwizzle(ivci.components.b), string_VkComponentSwizzle(ivci.components.a),
85859bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        validation_error_map[VALIDATION_ERROR_00412]);
85865ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
85875ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            }
8588d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        }
85895ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        // Verify correct attachment usage flags
85906600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        for (uint32_t subpass = 0; subpass < rpci->subpassCount; subpass++) {
85916600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify input attachments:
85923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
85939bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].inputAttachmentCount, rpci->pSubpasses[subpass].pInputAttachments,
85949bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                           pCreateInfo, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VALIDATION_ERROR_00407);
85956600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify color attachments:
85963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
85979bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].colorAttachmentCount, rpci->pSubpasses[subpass].pColorAttachments,
85989bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                           pCreateInfo, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VALIDATION_ERROR_00405);
85996600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify depth/stencil attachments:
86006600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (rpci->pSubpasses[subpass].pDepthStencilAttachment != nullptr) {
86013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= MatchUsage(dev_data, 1, rpci->pSubpasses[subpass].pDepthStencilAttachment, pCreateInfo,
86023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                   VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VALIDATION_ERROR_00406);
86036600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
86046600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
86056600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
86066fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    // Verify FB dimensions are within physical device limits
86079bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->width > dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth) {
86083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
86093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        VALIDATION_ERROR_00413, "DS",
86103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width exceeds physical device limits. "
86113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested width: %u, device max: %u\n"
86123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
86133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->width, dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth,
86143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_00413]);
86159bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
86169bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->height > dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight) {
86173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
86183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        VALIDATION_ERROR_00414, "DS",
86193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height exceeds physical device limits. "
86203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested height: %u, device max: %u\n"
86213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
86223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->height, dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight,
86233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_00414]);
86249bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
86259bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->layers > dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers) {
86263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
86273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        VALIDATION_ERROR_00415, "DS",
86283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers exceeds physical device limits. "
86293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested layers: %u, device max: %u\n"
86303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
86313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->layers, dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers,
86323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_00415]);
86336fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    }
8634c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    // Verify FB dimensions are greater than zero
8635c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->width <= 0) {
8636c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8637c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        VALIDATION_ERROR_02806, "DS",
8638c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width must be greater than zero. %s",
8639c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        validation_error_map[VALIDATION_ERROR_02806]);
8640c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
8641c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->height <= 0) {
8642c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8643c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        VALIDATION_ERROR_02807, "DS",
8644c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height must be greater than zero. %s",
8645c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        validation_error_map[VALIDATION_ERROR_02807]);
8646c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
8647c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->layers <= 0) {
8648c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8649c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        VALIDATION_ERROR_02808, "DS",
8650c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers must be greater than zero. %s",
8651c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        validation_error_map[VALIDATION_ERROR_02808]);
8652c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
86533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
86546600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
86556600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
865664c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis// Validate VkFramebufferCreateInfo state prior to calling down chain to create Framebuffer object
865764c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//  Return true if an error is encountered and callback returns true to skip call down chain
865864c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//   false indicates that call down chain should proceed
865964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlisstatic bool PreCallValidateCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
866064c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    // TODO : Verify that renderPass FB is created with is compatible with FB
86613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
86623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateFramebufferCreateInfo(dev_data, pCreateInfo);
86633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
866464c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis}
866564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
866654e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis// CreateFramebuffer state has been validated and call down chain completed so record new framebuffer object
866754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlisstatic void PostCallRecordCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo, VkFramebuffer fb) {
866854e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    // Shadow create info and store in map
8669c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    std::unique_ptr<FRAMEBUFFER_STATE> fb_state(
8670c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        new FRAMEBUFFER_STATE(fb, pCreateInfo, dev_data->renderPassMap[pCreateInfo->renderPass]->createInfo.ptr()));
867176f04ca0e692f9f15d5ef7e0c658c24d11f34ebcTobin Ehlis
867254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
867354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        VkImageView view = pCreateInfo->pAttachments[i];
86749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, view);
867579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        if (!view_state) {
867654e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis            continue;
867754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        }
867854e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        MT_FB_ATTACHMENT_INFO fb_info;
86799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        fb_info.mem = GetImageState(dev_data, view_state->create_info.image)->binding.mem;
8680883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        fb_info.view_state = view_state;
868179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        fb_info.image = view_state->create_info.image;
8682c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        fb_state->attachments.push_back(fb_info);
868354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    }
8684c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    dev_data->frameBufferMap[fb] = std::move(fb_state);
868554e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis}
868654e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis
868789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
8688bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) {
868956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
869064c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
86913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateCreateFramebuffer(dev_data, pCreateInfo);
869264c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    lock.unlock();
869364c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
86943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
869564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
86964a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
86976600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
86985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
869964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis        lock.lock();
870054e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        PostCallRecordCreateFramebuffer(dev_data, pCreateInfo, *pFramebuffer);
870154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        lock.unlock();
87025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
87045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
87064e11bb1277f55311686a42000520791e1db1dd7bbungemanstatic bool FindDependency(const uint32_t index, const uint32_t dependent, const std::vector<DAGNode> &subpass_to_node,
8707e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           std::unordered_set<uint32_t> &processed_nodes) {
87085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If we have already checked this node we have not found a dependency path so return false.
8709cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (processed_nodes.count(index)) return false;
87105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    processed_nodes.insert(index);
87115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
87125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Look for a dependency path. If one exists return true else recurse on the previous nodes.
87134e11bb1277f55311686a42000520791e1db1dd7bbungeman    if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) {
87145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto elem : node.prev) {
8715cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) return true;
87165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
8718e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        return true;
87195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8720e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
87215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
87234e11bb1277f55311686a42000520791e1db1dd7bbungemanstatic bool CheckDependencyExists(const layer_data *dev_data, const uint32_t subpass,
87243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                  const std::vector<uint32_t> &dependent_subpasses, const std::vector<DAGNode> &subpass_to_node,
87253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                  bool &skip) {
8726e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = true;
87275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through all subpasses that share the same attachment and make sure a dependency exists
87285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
8729cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (static_cast<uint32_t>(subpass) == dependent_subpasses[k]) continue;
87305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const DAGNode &node = subpass_to_node[subpass];
87315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Check for a specified dependency between the two nodes. If one exists we are done.
87325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]);
87335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]);
87345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
87357655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            // If no dependency exits an implicit dependency still might. If not, throw an error.
87365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            std::unordered_set<uint32_t> processed_nodes;
87377655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            if (!(FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) ||
8738bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                  FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes))) {
87393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
87403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
87413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "A dependency between subpasses %d and %d must exist but one is not specified.", subpass,
87423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                dependent_subpasses[k]);
8743e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                result = false;
87445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
87455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
87485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
87508860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, const int index,
87513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip) {
87525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
87535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If this node writes to the attachment return true as next nodes need to preserve the attachment.
87545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
87555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
8756cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pColorAttachments[j].attachment) return true;
87575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8758a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
8759a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour        if (attachment == subpass.pInputAttachments[j].attachment) return true;
8760a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    }
87615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
8762cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pDepthStencilAttachment->attachment) return true;
87635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8764e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
87655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through previous nodes and see if any of them write to the attachment.
87665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto elem : node.prev) {
87673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        result |= CheckPreserved(dev_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip);
87685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If the attachment was written to by a previous node than this node needs to preserve it.
87705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result && depth > 0) {
8771e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        bool has_preserved = false;
87725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
87735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (subpass.pPreserveAttachments[j] == attachment) {
8774e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                has_preserved = true;
87755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                break;
87765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
87775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8778e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        if (!has_preserved) {
87793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
87803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
87813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
87825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
87855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8787cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class T>
8788cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskibool isRangeOverlapping(T offset1, T size1, T offset2, T size2) {
87895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
87905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis           ((offset1 > offset2) && (offset1 < (offset2 + size2)));
87915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
87935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
87945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
87955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
87965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8798c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE const *framebuffer,
8799127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                 RENDER_PASS_STATE const *renderPass) {
88003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
8801fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pFramebufferInfo = framebuffer->createInfo.ptr();
8802fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pCreateInfo = renderPass->createInfo.ptr();
8803bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto const &subpass_to_node = renderPass->subpassToNode;
88045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount);
88055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount);
88065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount);
88075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find overlapping attachments
88085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
88095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) {
88105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewi = pFramebufferInfo->pAttachments[i];
88115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewj = pFramebufferInfo->pAttachments[j];
88125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (viewi == viewj) {
88135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
88145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
88155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
88165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
88179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_i = GetImageViewState(dev_data, viewi);
88189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_j = GetImageViewState(dev_data, viewj);
881979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (!view_state_i || !view_state_j) {
88205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
88215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
882279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_i = view_state_i->create_info;
882379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_j = view_state_j->create_info;
882479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (view_ci_i.image == view_ci_j.image && isRegionOverlapping(view_ci_i.subresourceRange, view_ci_j.subresourceRange)) {
88255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
88265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
88275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
88285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
88299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_i = GetImageState(dev_data, view_ci_i.image);
88309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_j = GetImageState(dev_data, view_ci_j.image);
88316d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (!image_data_i || !image_data_j) {
88325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
88335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8834e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            if (image_data_i->binding.mem == image_data_j->binding.mem &&
8835e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                isRangeOverlapping(image_data_i->binding.offset, image_data_i->binding.size, image_data_j->binding.offset,
8836e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                                   image_data_j->binding.size)) {
88375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
88385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
88395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
88405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
88415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
88425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
88435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t attachment = i;
88445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto other_attachment : overlapping_attachments[i]) {
88455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
88463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
8847df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
8848df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(framebuffer->framebuffer), __LINE__, VALIDATION_ERROR_00324, "DS",
8849df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "Attachment %d aliases attachment %d but doesn't "
8850df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
8851df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            attachment, other_attachment, validation_error_map[VALIDATION_ERROR_00324]);
88525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
88535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
88543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
8855df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
8856df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(framebuffer->framebuffer), __LINE__, VALIDATION_ERROR_00324, "DS",
8857df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "Attachment %d aliases attachment %d but doesn't "
8858df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
8859df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            other_attachment, attachment, validation_error_map[VALIDATION_ERROR_00324]);
88605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
88615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
88625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
88635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find for each attachment the subpasses that use them.
88641c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young    unordered_set<uint32_t> attachmentIndices;
88655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
88665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
88671c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young        attachmentIndices.clear();
88685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
88695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pInputAttachments[j].attachment;
8870cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
88715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            input_attachment_to_subpass[attachment].push_back(i);
88725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
88735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                input_attachment_to_subpass[overlapping_attachment].push_back(i);
88745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
88755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
88765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
88775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pColorAttachments[j].attachment;
8878cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
88795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
88805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
88815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
88825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
88831c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            attachmentIndices.insert(attachment);
88845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
88855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
88865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
88875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
88885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
88895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
88905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
88911c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young
88921c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            if (attachmentIndices.count(attachment)) {
88933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
8894df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8895df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
88968860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                            "Cannot use same attachment (%u) as both color and depth output in same subpass (%u).", attachment, i);
88971c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            }
88985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
88995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If there is a dependency needed make sure one exists
89015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
89025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
89035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an input then all subpasses that output must have a dependency relationship
89045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
890593fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pInputAttachments[j].attachment;
8906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
89073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
89085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
89105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
891193fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pColorAttachments[j].attachment;
8912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
89133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
89143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip);
89155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
89175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
89183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
89193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip);
89205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
89235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // written.
89245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
89255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
89265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
89273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckPreserved(dev_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip);
89285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
89315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
893332f68580aa01aab3e923cb52915a1d3dd4e993c5Chris Forbesstatic bool CreatePassDAG(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo,
8934e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                          std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) {
89353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
89365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
89375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        DAGNode &subpass_node = subpass_to_node[i];
89385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        subpass_node.pass = i;
89395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
89415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
894266a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL || dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
894366a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            if (dependency.srcSubpass == dependency.dstSubpass) {
89443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
8945df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8946df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external.");
894766a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            }
894866a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        } else if (dependency.srcSubpass > dependency.dstSubpass) {
89493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
89503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
89513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Depedency graph must be specified such that an earlier pass cannot depend on a later pass.");
89525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (dependency.srcSubpass == dependency.dstSubpass) {
89535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            has_self_dependency[dependency.srcSubpass] = true;
89545c6aacf95832467d52b2fde1130b04bef559573aChris Forbes        } else {
89555c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
89565c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
89575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
89605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8961918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
896289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
8963bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
896456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
89653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
8966c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    spv_result_t spv_valid = SPV_SUCCESS;
8967b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
8968e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    if (!GetDisables(dev_data)->shader_validation) {
8969e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        // Use SPIRV-Tools validator to try and catch any issues with the module itself
8970e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_context ctx = spvContextCreate(SPV_ENV_VULKAN_1_0);
8971e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_const_binary_t binary{pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t)};
8972e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_diagnostic diag = nullptr;
8973b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
8974c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        spv_valid = spvValidate(ctx, &binary, &diag);
8975c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        if (spv_valid != SPV_SUCCESS) {
89765581a92674a04d2ef49fde417e657f64e3aeed69Mark Lobodzinski            if (!dev_data->device_extensions.nv_glsl_shader_enabled || (pCreateInfo->pCode[0] == spv::MagicNumber)) {
89773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data,
89783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                spv_valid == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
89793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
89803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
8981c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski            }
8982e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        }
89835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8984e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spvDiagnosticDestroy(diag);
8985e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spvContextDestroy(ctx);
8986b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
89873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
8988e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    }
89895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
89904a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult res = dev_data->dispatch_table.CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
89915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8992e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    if (res == VK_SUCCESS && !GetDisables(dev_data)->shader_validation) {
8993b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
8994c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        const auto new_shader_module = (SPV_SUCCESS == spv_valid ? new shader_module(pCreateInfo) : new shader_module());
8995c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        dev_data->shaderModuleMap[*pShaderModule] = unique_ptr<shader_module>(new_shader_module);
89965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
89985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
90004f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateAttachmentIndex(layer_data *dev_data, uint32_t attachment, uint32_t attachment_count, const char *type) {
90013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
90024f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (attachment >= attachment_count && attachment != VK_ATTACHMENT_UNUSED) {
90033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
90043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        VALIDATION_ERROR_00325, "DS",
90053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "CreateRenderPass: %s attachment %d must be less than the total number of attachments %d. %s", type,
90063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        attachment, attachment_count, validation_error_map[VALIDATION_ERROR_00325]);
90074f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
90083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
90094f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
90104f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9011bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool IsPowerOfTwo(unsigned x) { return x && !(x & (x - 1)); }
9012805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
90134f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateRenderpassAttachmentUsage(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo) {
90143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
90154f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
90164f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
90174f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS) {
90183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
90193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, VALIDATION_ERROR_00347, "DS",
90203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "CreateRenderPass: Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS. %s", i,
90213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_00347]);
90224f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
90234f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
90244f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pPreserveAttachments[j];
90254f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) {
90263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
90273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, VALIDATION_ERROR_00356, "DS",
90283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "CreateRenderPass:  Preserve attachment (%d) must not be VK_ATTACHMENT_UNUSED. %s", j,
90293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                validation_error_map[VALIDATION_ERROR_00356]);
90304f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            } else {
90313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Preserve");
90324f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
90334f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
90346a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
9035bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto subpass_performs_resolve =
9036bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            subpass.pResolveAttachments &&
9037bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            std::any_of(subpass.pResolveAttachments, subpass.pResolveAttachments + subpass.colorAttachmentCount,
9038bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        [](VkAttachmentReference ref) { return ref.attachment != VK_ATTACHMENT_UNUSED; });
90396a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
9040805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        unsigned sample_count = 0;
9041805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
90424f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
90434f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment;
90444f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (subpass.pResolveAttachments) {
90454f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                attachment = subpass.pResolveAttachments[j].attachment;
90463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Resolve");
90476a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
90483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                if (!skip && attachment != VK_ATTACHMENT_UNUSED &&
90496a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    pCreateInfo->pAttachments[attachment].samples != VK_SAMPLE_COUNT_1_BIT) {
90503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
90513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    0, __LINE__, VALIDATION_ERROR_00352, "DS",
90523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "CreateRenderPass:  Subpass %u requests multisample resolve into attachment %u, "
90533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "which must have VK_SAMPLE_COUNT_1_BIT but has %s. %s",
90543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    i, attachment, string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment].samples),
90553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    validation_error_map[VALIDATION_ERROR_00352]);
90566a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                }
90574f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
90584f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            attachment = subpass.pColorAttachments[j].attachment;
90593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Color");
90606a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
90613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            if (!skip && attachment != VK_ATTACHMENT_UNUSED) {
9062805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
9063805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
9064bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (subpass_performs_resolve && pCreateInfo->pAttachments[attachment].samples == VK_SAMPLE_COUNT_1_BIT) {
90653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
90663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    0, __LINE__, VALIDATION_ERROR_00351, "DS",
90673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "CreateRenderPass:  Subpass %u requests multisample resolve from attachment %u "
90683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "which has VK_SAMPLE_COUNT_1_BIT. %s",
90693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    i, attachment, validation_error_map[VALIDATION_ERROR_00351]);
9070dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                }
90716a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes            }
90724f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9073dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
90744f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
90754f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
90763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Depth stencil");
9077805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
90783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            if (!skip && attachment != VK_ATTACHMENT_UNUSED) {
9079805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
9080805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            }
90814f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9082dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
90834f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
90844f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pInputAttachments[j].attachment;
90853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Input");
90864f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9087805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
9088805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        if (sample_count && !IsPowerOfTwo(sample_count)) {
90893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
90903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, VALIDATION_ERROR_00337, "DS",
90913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "CreateRenderPass:  Subpass %u attempts to render to "
90923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "attachments with inconsistent sample counts. %s",
90933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            i, validation_error_map[VALIDATION_ERROR_00337]);
9094805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        }
90954f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
90963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
90974f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
90984f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
90995245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbesstatic void MarkAttachmentFirstUse(RENDER_PASS_STATE *render_pass,
91005245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                                   uint32_t index,
91015245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                                   bool is_read) {
91025245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes    if (index == VK_ATTACHMENT_UNUSED)
91035245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes        return;
91045245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes
91055245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes    if (!render_pass->attachment_first_read.count(index))
91065245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes        render_pass->attachment_first_read[index] = is_read;
91075245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes}
91085245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes
910989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
91104f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
91113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
911256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
91134f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
91144f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
91154f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    // TODO: As part of wrapping up the mem_tracker/core_validation merge the following routine should be consolidated with
91164f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    //       ValidateLayouts.
91173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateRenderpassAttachmentUsage(dev_data, pCreateInfo);
9118208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
91193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].srcStageMask, "vkCreateRenderPass()",
91203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                             VALIDATION_ERROR_00368, VALIDATION_ERROR_00370);
91213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].dstStageMask, "vkCreateRenderPass()",
91223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                             VALIDATION_ERROR_00369, VALIDATION_ERROR_00371);
9123208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
91243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
91253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateLayouts(dev_data, device, pCreateInfo);
9126ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    }
9127ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes    lock.unlock();
91284f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
91293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
91304f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
91314f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
91324f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
91334a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
9134ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes
91355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
91364f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        lock.lock();
91374f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
91384f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<bool> has_self_dependency(pCreateInfo->subpassCount);
91394f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount);
914032f68580aa01aab3e923cb52915a1d3dd4e993c5Chris Forbes        skip |= CreatePassDAG(dev_data, pCreateInfo, subpass_to_node, has_self_dependency);
91414f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9142127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        auto render_pass = unique_ptr<RENDER_PASS_STATE>(new RENDER_PASS_STATE(pCreateInfo));
914398cddf7090b5d5dcc382045867753ef703d1c3d3Chris Forbes        render_pass->renderPass = *pRenderPass;
9144cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->hasSelfDependency = has_self_dependency;
9145cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->subpassToNode = subpass_to_node;
9146db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
914787e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
914887e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
914987e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
91505245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pColorAttachments[j].attachment, false);
91519cde292b1c19c643b7c13018d9834cccfe6ef7eaChris Forbes
91525245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                // resolve attachments are considered to be written
91535245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                if (subpass.pResolveAttachments) {
91545245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                    MarkAttachmentFirstUse(render_pass.get(), subpass.pResolveAttachments[j].attachment, false);
91559cde292b1c19c643b7c13018d9834cccfe6ef7eaChris Forbes                }
915687e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
91575245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes            if (subpass.pDepthStencilAttachment) {
91585245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pDepthStencilAttachment->attachment, false);
915987e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
9160a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
91615245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pInputAttachments[j].attachment, true);
9162a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            }
916387e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        }
9164db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
9165fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        dev_data->renderPassMap[*pRenderPass] = std::move(render_pass);
91665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
91685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
91694f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9170eb4c61477130f69f48fdf3ac31cb82104181cc73Chris Forbesstatic bool validatePrimaryCommandBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, char const *cmd_name,
91719bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         UNIQUE_VALIDATION_ERROR_CODE error_code) {
91723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
91735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
91743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
91753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, error_code, "DS",
9176eb4c61477130f69f48fdf3ac31cb82104181cc73Chris Forbes                        "Cannot execute command %s on a secondary command buffer. %s", cmd_name,
91773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[error_code]);
91785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
91805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
91815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
91828860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool VerifyRenderAreaBounds(const layer_data *dev_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
91833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9184c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    const safe_VkFramebufferCreateInfo *pFramebufferInfo =
91859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        &GetFramebufferState(dev_data, pRenderPassBegin->framebuffer)->createInfo;
9186885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    if (pRenderPassBegin->renderArea.offset.x < 0 ||
9187885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > pFramebufferInfo->width ||
9188885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        pRenderPassBegin->renderArea.offset.y < 0 ||
9189885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.y + pRenderPassBegin->renderArea.extent.height) > pFramebufferInfo->height) {
91903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= static_cast<bool>(log_msg(
9191df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
9192885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            DRAWSTATE_INVALID_RENDER_AREA, "CORE",
9193885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "Cannot execute a render pass with renderArea not within the bound of the "
9194885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "framebuffer. RenderArea: x %d, y %d, width %d, height %d. Framebuffer: width %d, "
9195885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "height %d.",
9196885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.width,
9197885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.extent.height, pFramebufferInfo->width, pFramebufferInfo->height));
9198885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    }
91993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
9200885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine}
9201885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine
92021a65650f856376768d7b03ea2d080aaff87cacfdMark 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
92031a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// [load|store]Op flag must be checked
92041a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// TODO: The memory valid flag in DEVICE_MEM_INFO should probably be split to track the validity of stencil memory separately.
9205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <typename T>
9206cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool FormatSpecificLoadAndStoreOpSettings(VkFormat format, T color_depth_op, T stencil_op, T op) {
9207a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    if (color_depth_op != op && stencil_op != op) {
9208a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski        return false;
9209a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    }
921016769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton    bool check_color_depth_load_op = !FormatIsStencilOnly(format);
921116769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton    bool check_stencil_load_op = FormatIsDepthAndStencil(format) || !check_color_depth_load_op;
9212a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski
92130d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes    return ((check_color_depth_load_op && (color_depth_op == op)) ||
92140d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes            (check_stencil_load_op && (stencil_op == op)));
92151a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski}
92161a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski
9217bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
9218bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkSubpassContents contents) {
92193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
922056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9221b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
92229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
92239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr;
92249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr;
9225f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
9226308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski        if (render_pass_state) {
9227cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            uint32_t clear_op_size = 0;  // Make sure pClearValues is at least as large as last LOAD_OP_CLEAR
9228f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeFramebuffer = pRenderPassBegin->framebuffer;
9229308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            for (uint32_t i = 0; i < render_pass_state->createInfo.attachmentCount; ++i) {
9230f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9231308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                auto pAttachment = &render_pass_state->createInfo.pAttachments[i];
9232bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp, pAttachment->stencilLoadOp,
92331a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski                                                         VK_ATTACHMENT_LOAD_OP_CLEAR)) {
923492bc0680357019834b7529148ab6d73353ce02c7Mark Lobodzinski                    clear_op_size = static_cast<uint32_t>(i) + 1;
923516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
92369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
923716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
923816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9239f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9240db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9241bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE)) {
924216387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
92439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
924416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
924516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9246f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9247db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9248bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD)) {
924916387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
92509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9251f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
925216387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9253f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
925416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                }
9255308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                if (render_pass_state->attachment_first_read[i]) {
925616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
92579a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9258f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
925916387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9260f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
92615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
92625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
92636de3c6ffa0819ee37cd5cecee918b062145e2ff1Tobin Ehlis            if (clear_op_size > pRenderPassBegin->clearValueCount) {
92643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
9265369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
9266308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    reinterpret_cast<uint64_t &>(render_pass_state->renderPass), __LINE__, VALIDATION_ERROR_00442, "DS",
9267bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but there must "
9268bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "be at least %u entries in pClearValues array to account for the highest index attachment in renderPass "
9269cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "0x%" PRIx64
9270cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array "
9271bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "is indexed by attachment number so even if some pClearValues entries between 0 and %u correspond to "
9272bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "attachments that aren't cleared they will be ignored. %s",
9273308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    pRenderPassBegin->clearValueCount, clear_op_size, reinterpret_cast<uint64_t &>(render_pass_state->renderPass),
92745504d0369cbc97ad7c221eddbad439bfb83e3fb6Mark Lobodzinski                    clear_op_size, clear_op_size - 1, validation_error_map[VALIDATION_ERROR_00442]);
9275369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            }
9276369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            if (clear_op_size < pRenderPassBegin->clearValueCount) {
92773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
9278369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
9279308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    reinterpret_cast<uint64_t &>(render_pass_state->renderPass), __LINE__,
9280308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    DRAWSTATE_RENDERPASS_TOO_MANY_CLEAR_VALUES, "DS",
9281369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but only first %u "
92827bab3d8f0599701f6e26a2d76314588486ae99c9Mark Lobodzinski                    "entries in pClearValues array are used. The highest index of any attachment in renderPass 0x%" PRIx64
9283369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u - other pClearValues are ignored.",
9284308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    pRenderPassBegin->clearValueCount, clear_op_size, reinterpret_cast<uint64_t &>(render_pass_state->renderPass),
92857bab3d8f0599701f6e26a2d76314588486ae99c9Mark Lobodzinski                    clear_op_size - 1);
92863d71bca42a843966040d6ada9c029e0ec9f35ca6Tobin Ehlis            }
92873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin);
92883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= VerifyFramebufferAndRenderPassLayouts(dev_data, cb_node, pRenderPassBegin,
92893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                          GetFramebufferState(dev_data, pRenderPassBegin->framebuffer));
92903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= insideRenderPass(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_00440);
92913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateDependencies(dev_data, framebuffer, render_pass_state);
9292eb4c61477130f69f48fdf3ac31cb82104181cc73Chris Forbes            skip |= validatePrimaryCommandBuffer(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_00441);
92933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
9294baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBeginRenderPass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_00439);
92953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateCmd(dev_data, cb_node, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()");
92961ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(cb_node, CMD_BEGINRENDERPASS);
9297308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            cb_node->activeRenderPass = render_pass_state;
92985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // This is a shallow copy as that is all that is needed for now
9299f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeRenderPassBeginInfo = *pRenderPassBegin;
9300f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpass = 0;
9301f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpassContents = contents;
9302f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->framebuffers.insert(pRenderPassBegin->framebuffer);
9303883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            // Connect this framebuffer and its children to this cmdBuffer
9304883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            AddFramebufferBinding(dev_data, cb_node, framebuffer);
93055f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis            // transition attachments to the correct layouts for beginning of renderPass and first subpass
93065f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis            TransitionBeginRenderPassLayouts(dev_data, cb_node, render_pass_state, framebuffer);
93075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9309b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
93103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
93114a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
93125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
931589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
93163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
931756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9318b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
93199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
93205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
9321eb4c61477130f69f48fdf3ac31cb82104181cc73Chris Forbes        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_00459);
93223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdNextSubpass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_00457);
93233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()");
93241ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_NEXTSUBPASS);
93253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_00458);
932680281691386b37385846f21b38e8c9d4b12cc74eChris Forbes
9327fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        auto subpassCount = pCB->activeRenderPass->createInfo.subpassCount;
932880281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        if (pCB->activeSubpass == subpassCount - 1) {
93293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
93303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00453, "DS",
93313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdNextSubpass(): Attempted to advance beyond final subpass. %s",
93323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_00453]);
933380281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        }
93345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9335b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
933696ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
93373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
933896ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
93394a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdNextSubpass(commandBuffer, contents);
934096ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
934196ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    if (pCB) {
9342bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        lock.lock();
9343bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpass++;
9344bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpassContents = contents;
93455f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis        TransitionSubpassLayouts(dev_data, pCB, pCB->activeRenderPass, pCB->activeSubpass,
93469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                 GetFramebufferState(dev_data, pCB->activeRenderPassBeginInfo.framebuffer));
934796ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    }
93485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
935089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) {
93513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
935256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9353b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
93549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pCB = GetCBNode(dev_data, commandBuffer);
935555867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski    FRAMEBUFFER_STATE *framebuffer = NULL;
935658c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes    if (pCB) {
9357127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        RENDER_PASS_STATE *rp_state = pCB->activeRenderPass;
93589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        framebuffer = GetFramebufferState(dev_data, pCB->activeFramebuffer);
9359127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        if (rp_state) {
9360127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            if (pCB->activeSubpass != rp_state->createInfo.subpassCount - 1) {
93613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
93623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer), __LINE__,
93633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                VALIDATION_ERROR_00460, "DS", "vkCmdEndRenderPass(): Called before reaching final subpass. %s",
93643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                validation_error_map[VALIDATION_ERROR_00460]);
936502a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes            }
936602a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes
9367127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            for (size_t i = 0; i < rp_state->createInfo.attachmentCount; ++i) {
9368e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9369127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                auto pAttachment = &rp_state->createInfo.pAttachments[i];
9370bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp, pAttachment->stencilStoreOp,
9371bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VK_ATTACHMENT_STORE_OP_STORE)) {
937258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
93739a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
937458c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
937558c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
937658c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
9377db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp,
9378bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE)) {
937958c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
93809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
938158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
938258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
938358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
93845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
93855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
93865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass()", VALIDATION_ERROR_00464);
9388eb4c61477130f69f48fdf3ac31cb82104181cc73Chris Forbes        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass()", VALIDATION_ERROR_00465);
93893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdEndRenderPass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_00463);
93903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()");
93911ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_ENDRENDERPASS);
93920e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    }
93930e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    lock.unlock();
93940e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
93953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
93960e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
93974a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdEndRenderPass(commandBuffer);
93980e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
93990e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    if (pCB) {
94000e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes        lock.lock();
940155867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        TransitionFinalSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, framebuffer);
940258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeRenderPass = nullptr;
940358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeSubpass = 0;
940458c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeFramebuffer = VK_NULL_HANDLE;
94055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9408a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, uint32_t primaryAttach,
9409a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                        uint32_t secondaryAttach, const char *msg) {
9410df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9411df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   reinterpret_cast<uint64_t>(secondaryBuffer), __LINE__, VALIDATION_ERROR_02059, "DS",
9412df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "vkCmdExecuteCommands() called w/ invalid Secondary Cmd Buffer 0x%" PRIx64
9413df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   " which has a render pass "
9414df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "that is not compatible with the Primary Cmd Buffer current render pass. "
9415df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "Attachment %u is not compatible with %u: %s. %s",
94169bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                   reinterpret_cast<uint64_t &>(secondaryBuffer), primaryAttach, secondaryAttach, msg,
94179bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                   validation_error_map[VALIDATION_ERROR_02059]);
94185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9420a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9421a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, uint32_t primaryAttach,
9422a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkCommandBuffer secondaryBuffer, VkRenderPassCreateInfo const *secondaryPassCI,
9423e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                            uint32_t secondaryAttach, bool is_multi) {
94243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9425a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->attachmentCount <= primaryAttach) {
94265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primaryAttach = VK_ATTACHMENT_UNUSED;
94275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9428a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (secondaryPassCI->attachmentCount <= secondaryAttach) {
94295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondaryAttach = VK_ATTACHMENT_UNUSED;
94305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) {
94323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
94335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED) {
94353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
94363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "The first is unused while the second is not.");
94373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
94385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondaryAttach == VK_ATTACHMENT_UNUSED) {
94403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
94413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "The second is unused while the first is not.");
94423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
94435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9444a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].format != secondaryPassCI->pAttachments[secondaryAttach].format) {
94453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9446a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different formats.");
94475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9448a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].samples != secondaryPassCI->pAttachments[secondaryAttach].samples) {
94493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9450a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different samples.");
94515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9452a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (is_multi && primaryPassCI->pAttachments[primaryAttach].flags != secondaryPassCI->pAttachments[secondaryAttach].flags) {
94533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9454a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different flags.");
94555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
94575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9459a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9460a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9461a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *secondaryPassCI, const int subpass, bool is_multi) {
94623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9463a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &primary_desc = primaryPassCI->pSubpasses[subpass];
9464a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &secondary_desc = secondaryPassCI->pSubpasses[subpass];
94655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
94665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) {
94675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
94685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.inputAttachmentCount) {
94695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_input_attach = primary_desc.pInputAttachments[i].attachment;
94705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.inputAttachmentCount) {
94725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
94735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_input_attach, secondaryBuffer,
94753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_input_attach, is_multi);
94765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
94785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) {
94795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
94805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount) {
94815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_color_attach = primary_desc.pColorAttachments[i].attachment;
94825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount) {
94845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
94855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_color_attach, secondaryBuffer,
94873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_color_attach, is_multi);
94885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
94895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
94905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
94915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
94935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
94945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_resolve_attach, secondaryBuffer,
94963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_resolve_attach, is_multi);
94975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
94995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primary_desc.pDepthStencilAttachment) {
95005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
95015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_desc.pDepthStencilAttachment) {
95035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
95045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_depthstencil_attach, secondaryBuffer,
95063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            secondaryPassCI, secondary_depthstencil_attach, is_multi);
95073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
95085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9510a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// Verify that given renderPass CreateInfo for primary and secondary command buffers are compatible.
9511a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  This function deals directly with the CreateInfo, there are overloaded versions below that can take the renderPass handle and
9512a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  will then feed into this function
9513a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9514a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9515a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *secondaryPassCI) {
95163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9517a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis
9518a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->subpassCount != secondaryPassCI->subpassCount) {
95193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
95203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t>(primaryBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
95213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer 0x%" PRIx64
95223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        " that has a subpassCount of %u that is incompatible with the primary Cmd Buffer 0x%" PRIx64
95233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        " that has a subpassCount of %u.",
95243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t &>(secondaryBuffer), secondaryPassCI->subpassCount,
95253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t &>(primaryBuffer), primaryPassCI->subpassCount);
9526a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    } else {
9527a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        for (uint32_t i = 0; i < primaryPassCI->subpassCount; ++i) {
95283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateSubpassCompatibility(dev_data, primaryBuffer, primaryPassCI, secondaryBuffer, secondaryPassCI, i,
95293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                 primaryPassCI->subpassCount > 1);
9530a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
95315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
95335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9535e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
9536e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) {
95373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
95385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pSubCB->beginInfo.pInheritanceInfo) {
95393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
95405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9541c5b97dda856ff837638b3ebb7e231d5507c495a3Chris Forbes    VkFramebuffer primary_fb = pCB->activeFramebuffer;
95425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
95435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_fb != VK_NULL_HANDLE) {
95445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (primary_fb != secondary_fb) {
95453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
95463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t>(primaryBuffer), __LINE__, VALIDATION_ERROR_02060, "DS",
95473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdExecuteCommands() called w/ invalid secondary command buffer 0x%" PRIx64
95483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " which has a framebuffer 0x%" PRIx64
95493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " that is not the same as the primary command buffer's current active framebuffer 0x%" PRIx64 ". %s",
95503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(secondaryBuffer), reinterpret_cast<uint64_t &>(secondary_fb),
95513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t &>(primary_fb), validation_error_map[VALIDATION_ERROR_02060]);
95525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
95539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto fb = GetFramebufferState(dev_data, secondary_fb);
9554e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes        if (!fb) {
95553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
95563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<uint64_t>(primaryBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
95573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
95583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "which has invalid framebuffer 0x%" PRIx64 ".",
95593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            (void *)secondaryBuffer, (uint64_t)(secondary_fb));
95603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            return skip;
95615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
95629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_renderpass = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
9563a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if (cb_renderpass->renderPass != fb->createInfo.renderPass) {
95643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb->renderPassCreateInfo.ptr(), secondaryBuffer,
95653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                    cb_renderpass->createInfo.ptr());
9566a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
95675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
95695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9571e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
95723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
95735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<int> activeTypes;
95745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pCB->activeQueries) {
95755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
95765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end()) {
95775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
95785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pSubCB->beginInfo.pInheritanceInfo) {
95795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
95805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) {
95813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
95823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(pCB->commandBuffer),
95833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    __LINE__, VALIDATION_ERROR_02065, "DS",
95843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
95853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "which has invalid active query pool 0x%" PRIx64
95863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    ". Pipeline statistics is being queried so the command "
95873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "buffer must have all bits set on the queryPool. %s",
95883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    pCB->commandBuffer, reinterpret_cast<const uint64_t &>(queryPoolData->first),
95893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    validation_error_map[VALIDATION_ERROR_02065]);
95905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
95915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
95925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            activeTypes.insert(queryPoolData->second.createInfo.queryType);
95935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
95945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pSubCB->startedQueries) {
95965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
95975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
95983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
9599df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9600df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9601df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
9602df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "which has invalid active query pool 0x%" PRIx64
9603df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "of type %d but a query of that type has been started on "
9604df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "secondary Cmd Buffer 0x%p.",
9605df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        pCB->commandBuffer, reinterpret_cast<const uint64_t &>(queryPoolData->first),
9606df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        queryPoolData->second.createInfo.queryType, pSubCB->commandBuffer);
96075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96097bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
96109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto primary_pool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
96119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto secondary_pool = GetCommandPoolNode(dev_data, pSubCB->createInfo.commandPool);
96127bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    if (primary_pool && secondary_pool && (primary_pool->queueFamilyIndex != secondary_pool->queueFamilyIndex)) {
96133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9614226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9615226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    reinterpret_cast<uint64_t>(pSubCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_FAMILY, "DS",
9616226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "vkCmdExecuteCommands(): Primary command buffer 0x%p"
9617226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    " created in queue family %d has secondary command buffer 0x%p created in queue family %d.",
9618226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    pCB->commandBuffer, primary_pool->queueFamilyIndex, pSubCB->commandBuffer, secondary_pool->queueFamilyIndex);
96197bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
96207bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
96213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
96225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9624bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
9625bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
96263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
962756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9628b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
96299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
96305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
96315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        GLOBAL_CB_NODE *pSubCB = NULL;
96325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < commandBuffersCount; i++) {
96339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            pSubCB = GetCBNode(dev_data, pCommandBuffers[i]);
96340a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            assert(pSubCB);
96350a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) {
96363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
9637df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
963860f59be7ded9ccf2d57c36b2e0974cc2798cf844Tobin Ehlis                            reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_00156, "DS",
9639df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "vkCmdExecuteCommands() called w/ Primary Cmd Buffer 0x%p in element %u of pCommandBuffers "
9640df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "array. All cmd buffers in pCommandBuffers array must be secondary. %s",
964160f59be7ded9ccf2d57c36b2e0974cc2798cf844Tobin Ehlis                            pCommandBuffers[i], i, validation_error_map[VALIDATION_ERROR_00156]);
9642cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (pCB->activeRenderPass) {  // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
96439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto secondary_rp_state = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
96445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
96453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
96465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9647df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_02057, "DS",
9648414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) executed within render pass (0x%" PRIxLEAST64
96494b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set. %s",
9650226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], (uint64_t)pCB->activeRenderPass->renderPass,
96514b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        validation_error_map[VALIDATION_ERROR_02057]);
96525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                } else {
96535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Make sure render pass is compatible with parent command buffer pass if has continue
9654127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                    if (pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) {
96553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        skip |= validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass->createInfo.ptr(),
96563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                                pCommandBuffers[i], secondary_rp_state->createInfo.ptr());
9657a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                    }
96581af6125615cd6dd9735d32e2ee8684abeff28d41Tobin Ehlis                    //  If framebuffer for secondary CB is not NULL, then it must match active FB from primaryCB
96593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB);
96605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
96615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                string errorString = "";
96621af6125615cd6dd9735d32e2ee8684abeff28d41Tobin Ehlis                // secondaryCB must have been created w/ RP compatible w/ primaryCB active renderpass
9663127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                if ((pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) &&
9664fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(),
9665127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                                     secondary_rp_state->createInfo.ptr(), errorString)) {
96663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
96675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9668df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
9669414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) w/ render pass (0x%" PRIxLEAST64
9670414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        ") is incompatible w/ primary command buffer (0x%p) w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
9671226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->renderPass, commandBuffer,
9672ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes                        (uint64_t)pCB->activeRenderPass->renderPass, errorString.c_str());
96735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
96745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
96755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO(mlentine): Move more logic into this method
96763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB);
96773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateCommandBufferState(dev_data, pSubCB, "vkCmdExecuteCommands()", 0);
96785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary cmdBuffers are considered pending execution starting w/
96795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // being recorded
96805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
96815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (dev_data->globalInFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->globalInFlightCmdBuffers.end()) {
96823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
96833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(pCB->commandBuffer),
96843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    __LINE__, VALIDATION_ERROR_00154, "DS",
96853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Attempt to simultaneously execute command buffer 0x%p"
96863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set! %s",
96873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    pCB->commandBuffer, validation_error_map[VALIDATION_ERROR_00154]);
96885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
96895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
96905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
96913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
96925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9693df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
9694226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) "
9695226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer "
9696226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "(0x%p) to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
969783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "set, even though it does.",
9698226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], pCB->commandBuffer);
96995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
97005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
97015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
9702f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes            if (!pCB->activeQueries.empty() && !dev_data->enabled_features.inheritedQueries) {
97033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
9704cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9705cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_02062, "DS",
9706cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer "
9707cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "(0x%p) cannot be submitted with a query in "
9708cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "flight and inherited queries not "
9709cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "supported on this device. %s",
9710cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            pCommandBuffers[i], validation_error_map[VALIDATION_ERROR_02062]);
97115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
97128567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            // Propagate layout transitions to the primary cmd buffer
97138567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            for (auto ilm_entry : pSubCB->imageLayoutMap) {
971455867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski                SetLayout(dev_data, pCB, ilm_entry.first, ilm_entry.second);
97158567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            }
97165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pSubCB->primaryCommandBuffer = pCB->commandBuffer;
97175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer);
97185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->globalInFlightCmdBuffers.insert(pSubCB->commandBuffer);
9719d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            for (auto &function : pSubCB->queryUpdates) {
9720d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine                pCB->queryUpdates.push_back(function);
9721d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            }
97225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9723eb4c61477130f69f48fdf3ac31cb82104181cc73Chris Forbes        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteCommands()", VALIDATION_ERROR_00163);
9724f5a52627a6576d3d532cd1f2e1be6d9987aeda7fChris Forbes        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdExecuteCommands()",
97253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                      VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_00162);
9726f5a52627a6576d3d532cd1f2e1be6d9987aeda7fChris Forbes        skip |= ValidateCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteCommands()");
97271ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_EXECUTECOMMANDS);
97285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9729b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
97303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
97315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9733bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
9734bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         void **ppData) {
973556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
97365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
97373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
97385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
9739b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
97409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
9741cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    if (mem_info) {
9742f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        // TODO : This could me more fine-grained to track just region that is valid
9743f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        mem_info->global_valid = true;
9744623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        auto end_offset = (VK_WHOLE_SIZE == size) ? mem_info->alloc_info.allocationSize - 1 : offset + size - 1;
97453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateMapImageLayouts(dev_data, device, mem_info, offset, end_offset);
9746cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        // TODO : Do we need to create new "bound_range" for the mapped range?
9747623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        SetMemRangesValid(dev_data, mem_info, offset, end_offset);
9748cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        if ((dev_data->phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
9749b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
97503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
97513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           (uint64_t)mem, __LINE__, VALIDATION_ERROR_00629, "MEM",
97523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj 0x%" PRIxLEAST64 ". %s",
97533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           (uint64_t)mem, validation_error_map[VALIDATION_ERROR_00629]);
97545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateMapMemRange(dev_data, mem, offset, size);
9757b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
97585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
97593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
97604a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.MapMemory(device, mem, offset, size, flags, ppData);
97617c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        if (VK_SUCCESS == result) {
97627c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.lock();
9763cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : What's the point of this range? See comment on creating new "bound_range" above, which may replace this
97647c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            storeMemRanges(dev_data, mem, offset, size);
97655f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            initializeAndTrackMemory(dev_data, mem, offset, size, ppData);
97667c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.unlock();
97677c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        }
97685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
97705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
977289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL UnmapMemory(VkDevice device, VkDeviceMemory mem) {
977356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
97743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
97755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9776b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
97773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= deleteMemRanges(dev_data, mem);
9778b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
97793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
97804a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UnmapMemory(device, mem);
97815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
97848860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool validateMemoryIsMapped(layer_data *dev_data, const char *funcName, uint32_t memRangeCount,
9785e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                   const VkMappedMemoryRange *pMemRanges) {
9786c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    bool skip = false;
97875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < memRangeCount; ++i) {
97889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, pMemRanges[i].memory);
978957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
9790f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            if (pMemRanges[i].size == VK_WHOLE_SIZE) {
9791f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if (mem_info->mem_range.offset > pMemRanges[i].offset) {
9792cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9793cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
9794cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VALIDATION_ERROR_00643, "MEM", "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER
9795cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                   ") is less than Memory Object's offset "
9796cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                   "(" PRINTF_SIZE_T_SPECIFIER "). %s",
9797cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    funcName, static_cast<size_t>(pMemRanges[i].offset),
9798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    static_cast<size_t>(mem_info->mem_range.offset), validation_error_map[VALIDATION_ERROR_00643]);
9799f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
9800f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            } else {
9801f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                const uint64_t data_end = (mem_info->mem_range.size == VK_WHOLE_SIZE)
9802f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              ? mem_info->alloc_info.allocationSize
9803f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              : (mem_info->mem_range.offset + mem_info->mem_range.size);
9804f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if ((mem_info->mem_range.offset > pMemRanges[i].offset) ||
9805f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                    (data_end < (pMemRanges[i].offset + pMemRanges[i].size))) {
9806c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski                    skip |=
9807f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9808f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                (uint64_t)pMemRanges[i].memory, __LINE__, VALIDATION_ERROR_00642, "MEM",
9809f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "%s: Flush/Invalidate size or offset (" PRINTF_SIZE_T_SPECIFIER ", " PRINTF_SIZE_T_SPECIFIER
9810f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                ") exceed the Memory Object's upper-bound "
9811f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "(" PRINTF_SIZE_T_SPECIFIER "). %s",
9812f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
9813f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(data_end),
9814f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                validation_error_map[VALIDATION_ERROR_00642]);
9815f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
98165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
98175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
98185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9819c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    return skip;
98205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9822bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic bool ValidateAndCopyNoncoherentMemoryToDriver(layer_data *dev_data, uint32_t mem_range_count,
9823bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                     const VkMappedMemoryRange *mem_ranges) {
9824bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    bool skip = false;
9825bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
98269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
982757fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
98285f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            if (mem_info->shadow_copy) {
98295f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
98305f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                        ? mem_info->mem_range.size
9831d8a53ade6b5501256798a8b4ec0bc14f72adc1faTobin Ehlis                                        : (mem_info->alloc_info.allocationSize - mem_info->mem_range.offset);
98325f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                char *data = static_cast<char *>(mem_info->shadow_copy);
98335f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = 0; j < mem_info->shadow_pad_size; ++j) {
98345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
9835bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9836bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem_ranges[i].memory, __LINE__,
9837bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        MEMTRACK_INVALID_MAP, "MEM", "Memory underflow was detected on mem obj 0x%" PRIxLEAST64,
9838bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        (uint64_t)mem_ranges[i].memory);
98395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
98405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
98415f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = (size + mem_info->shadow_pad_size); j < (2 * mem_info->shadow_pad_size + size); ++j) {
98425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
9843bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9844bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem_ranges[i].memory, __LINE__,
9845bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj 0x%" PRIxLEAST64,
9846bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        (uint64_t)mem_ranges[i].memory);
98475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
98485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
98495f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                memcpy(mem_info->p_driver_data, static_cast<void *>(data + mem_info->shadow_pad_size), (size_t)(size));
98505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
98515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
98525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9853bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    return skip;
98545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9856bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic void CopyNoncoherentMemoryFromDriver(layer_data *dev_data, uint32_t mem_range_count, const VkMappedMemoryRange *mem_ranges) {
9857bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
98589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
98595f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info && mem_info->shadow_copy) {
98605f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
98615f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    ? mem_info->mem_range.size
98625f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    : (mem_info->alloc_info.allocationSize - mem_ranges[i].offset);
98635f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            char *data = static_cast<char *>(mem_info->shadow_copy);
98645f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            memcpy(data + mem_info->shadow_pad_size, mem_info->p_driver_data, (size_t)(size));
98659e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski        }
98669e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski    }
98679e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski}
98689e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski
9869ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinskistatic bool ValidateMappedMemoryRangeDeviceLimits(layer_data *dev_data, const char *func_name, uint32_t mem_range_count,
9870ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                                                  const VkMappedMemoryRange *mem_ranges) {
9871ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    bool skip = false;
9872ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
9873ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        uint64_t atom_size = dev_data->phys_dev_properties.properties.limits.nonCoherentAtomSize;
987416769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(mem_ranges[i].offset, atom_size) != 0) {
9875df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9876df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(mem_ranges->memory), __LINE__, VALIDATION_ERROR_00644, "MEM",
9877ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Offset in pMemRanges[%d] is 0x%" PRIxLEAST64
9878ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
9879ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            func_name, i, mem_ranges[i].offset, atom_size, validation_error_map[VALIDATION_ERROR_00644]);
9880ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
988116769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if ((mem_ranges[i].size != VK_WHOLE_SIZE) && (SafeModulo(mem_ranges[i].size, atom_size) != 0)) {
9882df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9883df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(mem_ranges->memory), __LINE__, VALIDATION_ERROR_00645, "MEM",
9884ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Size in pMemRanges[%d] is 0x%" PRIxLEAST64
9885ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
9886ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            func_name, i, mem_ranges[i].size, atom_size, validation_error_map[VALIDATION_ERROR_00645]);
9887ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
9888ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    }
9889ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    return skip;
9890ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski}
9891ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski
989280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateFlushMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
989380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                   const VkMappedMemoryRange *mem_ranges) {
989480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
989580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
989680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= ValidateAndCopyNoncoherentMemoryToDriver(dev_data, mem_range_count, mem_ranges);
989780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkFlushMappedMemoryRanges", mem_range_count, mem_ranges);
989880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
989980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
990080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
9901bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
9902bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                       const VkMappedMemoryRange *pMemRanges) {
99035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
990456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
99055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
990680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateFlushMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
99074a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
99085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
99095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
99105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
991280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
991380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                        const VkMappedMemoryRange *mem_ranges) {
991480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
991580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
991680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkInvalidateMappedMemoryRanges", mem_range_count, mem_ranges);
991780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
991880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
991980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
992080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic void PostCallRecordInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
992180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                       const VkMappedMemoryRange *mem_ranges) {
992280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
992380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    // Update our shadow copy with modified driver data
992480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    CopyNoncoherentMemoryFromDriver(dev_data, mem_range_count, mem_ranges);
992580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
992680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
9927bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL InvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
9928bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                            const VkMappedMemoryRange *pMemRanges) {
99295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
993056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
99315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
993280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
99334a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
993480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        if (result == VK_SUCCESS) {
993580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski            PostCallRecordInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges);
993680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        }
99375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
99385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
99395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9941160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic bool PreCallValidateBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
9942160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                           VkDeviceSize memoryOffset) {
99430109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski    bool skip = false;
99441facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
9945160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
994694c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        // Track objects tied to memory
994747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        uint64_t image_handle = reinterpret_cast<uint64_t &>(image);
99487a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip = ValidateSetMemBinding(dev_data, mem, image_handle, kVulkanObjectTypeImage, "vkBindImageMemory()");
9949ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        if (!image_state->memory_requirements_checked) {
9950ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // There's not an explicit requirement in the spec to call vkGetImageMemoryRequirements() prior to calling
9951341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // BindImageMemory but it's implied in that memory being bound must conform with VkMemoryRequirements from
9952341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // vkGetImageMemoryRequirements()
99530109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
99540109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle, __LINE__, DRAWSTATE_INVALID_IMAGE, "DS",
99550109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            "vkBindImageMemory(): Binding memory to image 0x%" PRIxLEAST64
99560109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            " but vkGetImageMemoryRequirements() has not been called on that image.",
99570109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle);
9958ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // Make the call for them so we can verify the state
9959ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.unlock();
9960341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            dev_data->dispatch_table.GetImageMemoryRequirements(dev_data->device, image, &image_state->requirements);
9961ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.lock();
9962ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        }
996347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
99640ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Validate bound memory range information
99659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
996657fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
99670ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= ValidateInsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
99680ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                                   image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR, "vkBindImageMemory()");
996974300755ed9ec780d6073af71e47f201217008d6Cort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, image_state->requirements.memoryTypeBits, "vkBindImageMemory()",
99700109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                                        VALIDATION_ERROR_00806);
997147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
9972160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
9973160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements alignment
997416769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(memoryOffset, image_state->requirements.alignment) != 0) {
9975160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
9976160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            image_handle, __LINE__, VALIDATION_ERROR_02178, "DS",
9977160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindImageMemory(): memoryOffset is 0x%" PRIxLEAST64
9978160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be an integer multiple of the "
9979160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
9980160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
9981160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            memoryOffset, image_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_02178]);
9982160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
9983160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
9984160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements size
9985160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        if (image_state->requirements.size > mem_info->alloc_info.allocationSize - memoryOffset) {
9986160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
9987160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            image_handle, __LINE__, VALIDATION_ERROR_02179, "DS",
9988160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindImageMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
9989160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be at least as large as "
9990160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
9991160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
9992160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            mem_info->alloc_info.allocationSize - memoryOffset, image_state->requirements.size,
9993160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            validation_error_map[VALIDATION_ERROR_02179]);
9994160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
9995341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
9996341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    return skip;
9997341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
999847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
9999160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic void PostCallRecordBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
10000160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                          VkDeviceSize memoryOffset) {
10001341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (image_state) {
10002160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
100030ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Track bound memory range information
100040ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto mem_info = GetMemObjInfo(dev_data, mem);
100050ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        if (mem_info) {
100060ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            InsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
100070ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                   image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR);
100080ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
100090ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
10010c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
10011c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        uint64_t image_handle = reinterpret_cast<uint64_t &>(image);
100127a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        SetMemBinding(dev_data, mem, image_handle, kVulkanObjectTypeImage, "vkBindImageMemory()");
10013c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
10014341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.mem = mem;
10015341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.offset = memoryOffset;
10016341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.size = image_state->requirements.size;
10017341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
10018341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
10019341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton
10020341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
10021341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10022341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
10023160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    auto image_state = GetImageState(dev_data, image);
10024160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    bool skip = PreCallValidateBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
10025341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (!skip) {
10026341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        result = dev_data->dispatch_table.BindImageMemory(device, image, mem, memoryOffset);
10027341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        if (result == VK_SUCCESS) {
10028160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            PostCallRecordBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
1002994c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        }
100305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1003489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL SetEvent(VkDevice device, VkEvent event) {
100353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
100363ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1003756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10038b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
100399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto event_state = GetEventNode(dev_data, event);
100404710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    if (event_state) {
100414710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->needsSignaled = false;
100424710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->stageMask = VK_PIPELINE_STAGE_HOST_BIT;
100434710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state->write_in_use) {
100443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
100453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
100463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Cannot call vkSetEvent() on event 0x%" PRIxLEAST64 " that is already in use by a command buffer.",
100473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<const uint64_t &>(event));
100483ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis        }
100493ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    }
10050b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
100516fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // Host setting event is visible to all queues immediately so update stageMask for any queue that's seen this event
100526fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // TODO : For correctness this needs separate fix to verify that app doesn't make incorrect assumptions about the
100536fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // ordering of this command in relation to vkCmd[Set|Reset]Events (see GH297)
100546fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    for (auto queue_data : dev_data->queueMap) {
100556fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        auto event_entry = queue_data.second.eventToStageMap.find(event);
100566fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        if (event_entry != queue_data.second.eventToStageMap.end()) {
100576fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis            event_entry->second |= VK_PIPELINE_STAGE_HOST_BIT;
100586fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        }
100596fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    }
100603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) result = dev_data->dispatch_table.SetEvent(device, event);
100615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10064bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
10065bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               VkFence fence) {
1006656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
100675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
100683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
10069b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
100709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
100719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
10072651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
100734b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    // First verify that fence is not in use
100743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateFenceForSubmit(dev_data, pFence);
10075651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
100769867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence) {
1007793ccd9708dad3ffb58a3fc09a3d61cc5fe1569f8Mark Lobodzinski        SubmitFence(pQueue, pFence, std::max(1u, bindInfoCount));
100784b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    }
10079651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
100801344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) {
100811344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx];
100825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Track objects tied to memory
100831344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.bufferBindCount; j++) {
100841344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pBufferBinds[j].bindCount; k++) {
10085f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pBufferBinds[j].pBinds[k];
10086f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
10087ece0e981ee4a5ad2572d146a89fc64d699d79f36Chris Forbes                                        (uint64_t)bindInfo.pBufferBinds[j].buffer, kVulkanObjectTypeBuffer))
100883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
100895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
100905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
100911344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageOpaqueBindCount; j++) {
100921344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageOpaqueBinds[j].bindCount; k++) {
10093f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageOpaqueBinds[j].pBinds[k];
10094f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
10095ece0e981ee4a5ad2572d146a89fc64d699d79f36Chris Forbes                                        (uint64_t)bindInfo.pImageOpaqueBinds[j].image, kVulkanObjectTypeImage))
100963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
100975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
100985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
100991344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageBindCount; j++) {
101001344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageBinds[j].bindCount; k++) {
10101f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageBinds[j].pBinds[k];
10102f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                // TODO: This size is broken for non-opaque bindings, need to update to comprehend full sparse binding data
10103f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                VkDeviceSize size = sparse_binding.extent.depth * sparse_binding.extent.height * sparse_binding.extent.width * 4;
10104f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, size},
10105ece0e981ee4a5ad2572d146a89fc64d699d79f36Chris Forbes                                        (uint64_t)bindInfo.pImageBinds[j].image, kVulkanObjectTypeImage))
101063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
101075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
101085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
101099867daedbf52debc77d6568162ee21e071699b80Chris Forbes
101109867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<SEMAPHORE_WAIT> semaphore_waits;
101119867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<VkSemaphore> semaphore_signals;
101121344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
1011301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pWaitSemaphores[i];
101149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
1011501a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
1011601a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
101179867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
101189867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
101199867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        pSemaphore->in_use.fetch_add(1);
101209867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
101219867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = VK_NULL_HANDLE;
1012201a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                    pSemaphore->signaled = false;
101231344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
101243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
101253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
101263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkQueueBindSparse: Queue 0x%p is waiting on semaphore 0x%" PRIx64
101273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " that has no way to be signaled.",
101283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    queue, reinterpret_cast<const uint64_t &>(semaphore));
101295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
101305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
101315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
101321344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
1013301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pSignalSemaphores[i];
101349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
1013501a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
1013601a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
101373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
101383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                   reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
101393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                   "vkQueueBindSparse: Queue 0x%p is signaling semaphore 0x%" PRIx64
101403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                   ", but that semaphore is already signaled.",
101413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                   queue, reinterpret_cast<const uint64_t &>(semaphore));
10142bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                } else {
101439867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = queue;
101449867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
101459867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaled = true;
101469867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->in_use.fetch_add(1);
101479867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    semaphore_signals.push_back(semaphore);
101489867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
101495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
101505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
101519867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10152bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), semaphore_waits, semaphore_signals,
101539867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         bindIdx == bindInfoCount - 1 ? fence : VK_NULL_HANDLE);
101545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101559867daedbf52debc77d6568162ee21e071699b80Chris Forbes
101569867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence && !bindInfoCount) {
101579867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // No work to do, just dropping a fence in the queue by itself.
10158bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
101599867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         fence);
101609867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
101619867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10162b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
101635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
101643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) return dev_data->dispatch_table.QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
101655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
101665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
101675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1016989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
1017089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
1017156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
101724a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
101735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10174b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10175bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        SEMAPHORE_NODE *sNode = &dev_data->semaphoreMap[*pSemaphore];
101769867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.first = VK_NULL_HANDLE;
101779867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.second = 0;
101781344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        sNode->signaled = false;
101795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
101815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10183bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
10184bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
1018556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
101864a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateEvent(device, pCreateInfo, pAllocator, pEvent);
101875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10188b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
101895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].needsSignaled = false;
10190293ecfc5e69ed3978a8c04518166d828294870a4Tony Barbour        dev_data->eventMap[*pEvent].write_in_use = 0;
101915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
101925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
101945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
101969ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinskistatic bool PreCallValidateCreateSwapchainKHR(layer_data *dev_data, const char *func_name,
101979ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              VkSwapchainCreateInfoKHR const *pCreateInfo, SURFACE_STATE *surface_state,
101989ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              SWAPCHAIN_NODE *old_swapchain_state) {
10199d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    auto most_recent_swapchain = surface_state->swapchain ? surface_state->swapchain : surface_state->old_swapchain;
10200d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
102014bd5f453535de3d3423ff1f9995b4acb15f791d2Chris Forbes    // TODO: revisit this. some of these rules are being relaxed.
10202d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (most_recent_swapchain != old_swapchain_state || (surface_state->old_swapchain && surface_state->swapchain)) {
10203d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10204d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes                    reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_ALREADY_EXISTS, "DS",
102059ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface has an existing swapchain other than oldSwapchain", func_name))
10206d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10207d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
10208d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (old_swapchain_state && old_swapchain_state->createInfo.surface != pCreateInfo->surface) {
10209d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10210d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes                    reinterpret_cast<uint64_t const &>(pCreateInfo->oldSwapchain), __LINE__, DRAWSTATE_SWAPCHAIN_WRONG_SURFACE,
102119ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "DS", "%s: pCreateInfo->oldSwapchain's surface is not pCreateInfo->surface", func_name))
10212d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10213d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
102149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
102157de258f87ca1192db116a66b209253793d276ebcChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState == UNCALLED) {
102167de258f87ca1192db116a66b209253793d276ebcChris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
102177de258f87ca1192db116a66b209253793d276ebcChris Forbes                    reinterpret_cast<uint64_t>(dev_data->physical_device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
102189ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface capabilities not retrieved for this physical device", func_name))
102197de258f87ca1192db116a66b209253793d276ebcChris Forbes            return true;
10220cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // have valid capabilities
102215c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        auto &capabilities = physical_device_state->surfaceCapabilities;
102229ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->minImageCount against VkSurfaceCapabilitiesKHR::{min|max}ImageCount:
102232fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if (pCreateInfo->minImageCount < capabilities.minImageCount) {
102242fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
102252fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02331, "DS",
102269ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
102272fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
102289ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
102292fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02331]))
102302fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                return true;
102312fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        }
102322fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
102332fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if ((capabilities.maxImageCount > 0) && (pCreateInfo->minImageCount > capabilities.maxImageCount)) {
102345c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
102352fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02332, "DS",
102369ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
102372fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
102389ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
102392fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02332]))
102405c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
102415c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
102422fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
102439ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageExtent against VkSurfaceCapabilitiesKHR::{current|min|max}ImageExtent:
102442e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width == kSurfaceSizeFromSwapchain) &&
102452e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width < capabilities.minImageExtent.width) ||
102462e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.width > capabilities.maxImageExtent.width) ||
102472e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height < capabilities.minImageExtent.height) ||
102482e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height > capabilities.maxImageExtent.height))) {
102495c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
102502fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02334, "DS",
102519ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is outside the bounds returned by "
102529ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (%d,%d), minImageExtent = (%d,%d), "
102539ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "maxImageExtent = (%d,%d). %s",
102549ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
102559ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height, capabilities.minImageExtent.width,
102569ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.minImageExtent.height, capabilities.maxImageExtent.width, capabilities.maxImageExtent.height,
102572fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02334]))
102585c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
102595c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
102609ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->preTransform should have exactly one bit set, and that bit must also be set in
102619ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedTransforms.
102625c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->preTransform || (pCreateInfo->preTransform & (pCreateInfo->preTransform - 1)) ||
102635c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !(pCreateInfo->preTransform & capabilities.supportedTransforms)) {
102649ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
102659ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
102665c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
102675c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
102685c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
102699ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->preTransform (i.e. %s).  Supported values are:\n", func_name,
102705c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    string_VkSurfaceTransformFlagBitsKHR(pCreateInfo->preTransform));
102715c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
102725c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
102735c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
102745c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedTransforms) {
102755c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkSurfaceTransformFlagBitsKHR((VkSurfaceTransformFlagBitsKHR)(1 << i));
102765c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
102775c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
102785c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
102795c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
102805c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
102815c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
102822fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_02339, "DS", "%s. %s",
102832fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        errorString.c_str(), validation_error_map[VALIDATION_ERROR_02339]))
102845c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
102855c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
102867b0d28d116977b91892f354e002edd760bdb86cbChris Forbes
102879ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->compositeAlpha should have exactly one bit set, and that bit must also be set in
102889ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedCompositeAlpha
102895c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->compositeAlpha || (pCreateInfo->compositeAlpha & (pCreateInfo->compositeAlpha - 1)) ||
102905c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !((pCreateInfo->compositeAlpha) & capabilities.supportedCompositeAlpha)) {
102919ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
102929ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
102935c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
102945c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
102955c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
102969ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->compositeAlpha (i.e. %s).  Supported values are:\n",
102979ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    func_name, string_VkCompositeAlphaFlagBitsKHR(pCreateInfo->compositeAlpha));
102985c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
102995c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
103005c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
103015c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedCompositeAlpha) {
103025c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkCompositeAlphaFlagBitsKHR((VkCompositeAlphaFlagBitsKHR)(1 << i));
103035c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
103045c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
103055c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
103065c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
103075c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
103085c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103092fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_02340, "DS", "%s. %s",
103102fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        errorString.c_str(), validation_error_map[VALIDATION_ERROR_02340]))
103115c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
103125c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
103139ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageArrayLayers against VkSurfaceCapabilitiesKHR::maxImageArrayLayers:
103145c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if ((pCreateInfo->imageArrayLayers < 1) || (pCreateInfo->imageArrayLayers > capabilities.maxImageArrayLayers)) {
103155c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103162fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02335, "DS",
103179ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported imageArrayLayers (i.e. %d).  Minimum value is 1, maximum value is %d. %s",
103189ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageArrayLayers, capabilities.maxImageArrayLayers,
103192fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02335]))
103205c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
103215c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
103229ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageUsage against VkSurfaceCapabilitiesKHR::supportedUsageFlags:
103235c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (pCreateInfo->imageUsage != (pCreateInfo->imageUsage & capabilities.supportedUsageFlags)) {
103245c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103252fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02336, "DS",
103269ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported pCreateInfo->imageUsage (i.e. 0x%08x).  Supported flag bits are 0x%08x. %s",
103279ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageUsage, capabilities.supportedUsageFlags,
103289ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        validation_error_map[VALIDATION_ERROR_02336]))
103295c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
103305c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
103317de258f87ca1192db116a66b209253793d276ebcChris Forbes    }
10332d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
103339ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfaceFormatsKHR():
103345faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState != QUERY_DETAILS) {
103355faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103365faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
103379ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s called before calling vkGetPhysicalDeviceSurfaceFormatsKHR().", func_name))
103385faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            return true;
103395faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    } else {
103409ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageFormat against VkSurfaceFormatKHR::format:
103415faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundFormat = false;
103425faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundColorSpace = false;
103435faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundMatch = false;
103445faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        for (auto const &format : physical_device_state->surface_formats) {
103455faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (pCreateInfo->imageFormat == format.format) {
103469ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                // Validate pCreateInfo->imageColorSpace against VkSurfaceFormatKHR::colorSpace:
103475faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                foundFormat = true;
103485faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
103495faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundMatch = true;
103505faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    break;
103515faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
103525faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            } else {
103535faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
103545faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundColorSpace = true;
103555faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
103565faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
103575faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
103585faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (!foundMatch) {
103595faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (!foundFormat) {
103605faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103612fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                            reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02333, "DS",
10362bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageFormat (i.e. %d). %s", func_name,
10363bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            pCreateInfo->imageFormat, validation_error_map[VALIDATION_ERROR_02333]))
103642fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                    return true;
103652fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            }
103662fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (!foundColorSpace) {
103672fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103682fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                            reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02333, "DS",
10369bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageColorSpace (i.e. %d). %s", func_name,
10370bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            pCreateInfo->imageColorSpace, validation_error_map[VALIDATION_ERROR_02333]))
103715faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    return true;
103725faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
103735faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
103745faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
103755faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
103769ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfacePresentModesKHR():
103779e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState != QUERY_DETAILS) {
1037825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // FIFO is required to always be supported
103799e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pCreateInfo->presentMode != VK_PRESENT_MODE_FIFO_KHR) {
103809e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103819ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
103829ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called before calling vkGetPhysicalDeviceSurfacePresentModesKHR().", func_name))
103839e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
103849e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
103859e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    } else {
103869ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->presentMode against vkGetPhysicalDeviceSurfacePresentModesKHR():
10387bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        bool foundMatch = std::find(physical_device_state->present_modes.begin(), physical_device_state->present_modes.end(),
103889e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                    pCreateInfo->presentMode) != physical_device_state->present_modes.end();
103899e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (!foundMatch) {
103909e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103912fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02341, "DS",
103929ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported presentMode (i.e. %s). %s", func_name,
103932fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        string_VkPresentModeKHR(pCreateInfo->presentMode), validation_error_map[VALIDATION_ERROR_02341]))
103949e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
103959e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
103969e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
103979e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
10398d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    return false;
10399d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes}
10400d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
10401261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinskistatic void PostCallRecordCreateSwapchainKHR(layer_data *dev_data, VkResult result, const VkSwapchainCreateInfoKHR *pCreateInfo,
10402261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             VkSwapchainKHR *pSwapchain, SURFACE_STATE *surface_state,
10403261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             SWAPCHAIN_NODE *old_swapchain_state) {
104045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
10405b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10406ddc5201048319558ce66701163a4546ee957af19Chris Forbes        auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(pCreateInfo, *pSwapchain));
10407ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = swapchain_state.get();
10408ddc5201048319558ce66701163a4546ee957af19Chris Forbes        dev_data->device_extensions.swapchainMap[*pSwapchain] = std::move(swapchain_state);
10409ddc5201048319558ce66701163a4546ee957af19Chris Forbes    } else {
10410ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = nullptr;
104115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10412ddc5201048319558ce66701163a4546ee957af19Chris Forbes    // Spec requires that even if CreateSwapchainKHR fails, oldSwapchain behaves as replaced.
104135b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    if (old_swapchain_state) {
104145b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes        old_swapchain_state->replaced = true;
104155b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    }
10416ddc5201048319558ce66701163a4546ee957af19Chris Forbes    surface_state->old_swapchain = old_swapchain_state;
10417261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    return;
10418261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski}
10419261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10420261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
10421261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
1042256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
104239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(dev_data->instance_data, pCreateInfo->surface);
104249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto old_swapchain_state = GetSwapchainNode(dev_data, pCreateInfo->oldSwapchain);
10425261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
104269ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    if (PreCallValidateCreateSwapchainKHR(dev_data, "vkCreateSwapChainKHR()", pCreateInfo, surface_state, old_swapchain_state)) {
10427261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10428261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    }
10429261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10430261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    VkResult result = dev_data->dispatch_table.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
10431261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10432261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    PostCallRecordCreateSwapchainKHR(dev_data, result, pCreateInfo, pSwapchain, surface_state, old_swapchain_state);
10433ddc5201048319558ce66701163a4546ee957af19Chris Forbes
104345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
104355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
104365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10437bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
1043856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
104393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
104405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10441b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
104429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
10443b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swapchain_data) {
10444b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_data->images.size() > 0) {
10445b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis            for (auto swapchain_image : swapchain_data->images) {
104465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
104475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (image_sub != dev_data->imageSubresourceMap.end()) {
104485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    for (auto imgsubpair : image_sub->second) {
104495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
104505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if (image_item != dev_data->imageLayoutMap.end()) {
104515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            dev_data->imageLayoutMap.erase(image_item);
104525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
104535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
104545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    dev_data->imageSubresourceMap.erase(image_sub);
104555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
104563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip = ClearMemoryObjectBindings(dev_data, (uint64_t)swapchain_image, kVulkanObjectTypeSwapchainKHR);
1045794c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                dev_data->imageMap.erase(swapchain_image);
104585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
104595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10460ddc5201048319558ce66701163a4546ee957af19Chris Forbes
104619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
10462ddc5201048319558ce66701163a4546ee957af19Chris Forbes        if (surface_state) {
10463cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->swapchain == swapchain_data) surface_state->swapchain = nullptr;
10464cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->old_swapchain == swapchain_data) surface_state->old_swapchain = nullptr;
10465ddc5201048319558ce66701163a4546ee957af19Chris Forbes        }
10466ddc5201048319558ce66701163a4546ee957af19Chris Forbes
104675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->device_extensions.swapchainMap.erase(swapchain);
104685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10469b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
104703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
104715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
104725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10473bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount,
10474bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                     VkImage *pSwapchainImages) {
1047556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
104764a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
104775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
104785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS && pSwapchainImages != NULL) {
104795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This should never happen and is checked by param checker.
10480cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!pCount) return result;
10481b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
104825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const size_t count = *pCount;
104839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_node = GetSwapchainNode(dev_data, swapchain);
10484b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_node && !swapchain_node->images.empty()) {
104850801763633180d277d26a90343464bd11646056fTobin Ehlis            // TODO : Not sure I like the memcmp here, but it works
104860801763633180d277d26a90343464bd11646056fTobin Ehlis            const bool mismatch = (swapchain_node->images.size() != count ||
104870801763633180d277d26a90343464bd11646056fTobin Ehlis                                   memcmp(&swapchain_node->images[0], pSwapchainImages, sizeof(swapchain_node->images[0]) * count));
104885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mismatch) {
104895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // TODO: Verify against Valid Usage section of extension
104905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
104915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)swapchain, __LINE__, MEMTRACK_NONE, "SWAP_CHAIN",
10492414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkGetSwapchainInfoKHR(0x%" PRIx64
104935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        ", VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR) returned mismatching data",
104945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)(swapchain));
104955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
104965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
104975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < *pCount; ++i) {
104985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            IMAGE_LAYOUT_NODE image_layout_node;
104995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
105005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.format = swapchain_node->createInfo.imageFormat;
105016d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            // Add imageMap entries for each swapchain image
105026d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            VkImageCreateInfo image_ci = {};
10503eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.flags = 0;
10504eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.imageType = VK_IMAGE_TYPE_2D;
105056d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.format = swapchain_node->createInfo.imageFormat;
105066d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.width = swapchain_node->createInfo.imageExtent.width;
105076d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.height = swapchain_node->createInfo.imageExtent.height;
10508d1a9776c1a22ec99a3ef0dd44e7f85a78a04d1edTony Barbour            image_ci.extent.depth = 1;
10509eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.mipLevels = 1;
10510eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.arrayLayers = swapchain_node->createInfo.imageArrayLayers;
10511eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
10512eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
10513eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.usage = swapchain_node->createInfo.imageUsage;
105146d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.sharingMode = swapchain_node->createInfo.imageSharingMode;
105151facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            dev_data->imageMap[pSwapchainImages[i]] = unique_ptr<IMAGE_STATE>(new IMAGE_STATE(pSwapchainImages[i], &image_ci));
105161facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto &image_state = dev_data->imageMap[pSwapchainImages[i]];
105171facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->valid = false;
10518e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            image_state->binding.mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
105195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            swapchain_node->images.push_back(pSwapchainImages[i]);
105205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
105215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
105225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageLayoutMap[subpair] = image_layout_node;
105235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->device_extensions.imageToSwapchainMap[pSwapchainImages[i]] = swapchain;
105245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
105255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
105265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
105275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
105285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1052989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
1053056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
105313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
105325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
105336c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    std::lock_guard<std::mutex> lock(global_lock);
105349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
105351671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
105366c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
105379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
105386c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        if (pSemaphore && !pSemaphore->signaled) {
105393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
105403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
105413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
105423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPresentInfo->pWaitSemaphores[i]));
105435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
105446c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
10545249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
105466c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
105479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10548a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes        if (swapchain_data) {
10549a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes            if (pPresentInfo->pImageIndices[i] >= swapchain_data->images.size()) {
105503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
10551bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10552bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE,
10553bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "DS", "vkQueuePresentKHR: Swapchain image index too large (%u). There are only %u images in this swapchain.",
10554bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    pPresentInfo->pImageIndices[i], (uint32_t)swapchain_data->images.size());
10555bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            } else {
10556a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
105579a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, image);
105583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateImageMemoryIsValid(dev_data, image_state, "vkQueuePresentKHR()");
10559a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
105601facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                if (!image_state->acquired) {
105613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
10562bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10563bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
10564bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        DRAWSTATE_SWAPCHAIN_IMAGE_NOT_ACQUIRED, "DS",
10565bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        "vkQueuePresentKHR: Swapchain image index %u has not been acquired.", pPresentInfo->pImageIndices[i]);
10566a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                }
10567a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
10568a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                vector<VkImageLayout> layouts;
10569a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                if (FindLayouts(dev_data, image, layouts)) {
10570a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                    for (auto layout : layouts) {
10571a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        if (layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
105723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |=
105732fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
105742fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        reinterpret_cast<uint64_t &>(queue), __LINE__, VALIDATION_ERROR_01964, "DS",
105752fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "Images passed to present must be in layout "
105762fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR but is in %s. %s",
105772fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        string_VkImageLayout(layout), validation_error_map[VALIDATION_ERROR_01964]);
10578a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        }
105795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
105805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
105815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
105821671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
105831671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // All physical devices and queue families are required to be able
105841671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // to present to any native window on Android; require the
105851671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // application to have established support on any other platform.
105861671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            if (!dev_data->instance_data->androidSurfaceExtensionEnabled) {
105879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
105881671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                auto support_it = surface_state->gpu_queue_support.find({dev_data->physical_device, queue_state->queueFamilyIndex});
105891671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
105901671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                if (support_it == surface_state->gpu_queue_support.end()) {
105913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |=
105921671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
105931671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                                reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
10594cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_SWAPCHAIN_UNSUPPORTED_QUEUE, "DS",
10595cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkQueuePresentKHR: Presenting image without calling "
10596cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkGetPhysicalDeviceSurfaceSupportKHR");
105971671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                } else if (!support_it->second) {
105983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
10599cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10600cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__, VALIDATION_ERROR_01961, "DS",
10601cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkQueuePresentKHR: Presenting image on queue that cannot "
10602cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "present to this surface. %s",
10603cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_01961]);
106041671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                }
106051671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            }
106065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
106075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10608c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis    if (pPresentInfo && pPresentInfo->pNext) {
10609c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        // Verify ext struct
10610c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        struct std_header {
10611c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            VkStructureType sType;
10612c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            const void *pNext;
10613c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        };
10614c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        std_header *pnext = (std_header *)pPresentInfo->pNext;
10615c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        while (pnext) {
10616c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            if (VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR == pnext->sType) {
10617c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                VkPresentRegionsKHR *present_regions = (VkPresentRegionsKHR *)pnext;
10618c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
10619c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10620c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    assert(swapchain_data);
10621c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    VkPresentRegionKHR region = present_regions->pRegions[i];
10622c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    for (uint32_t j = 0; j < region.rectangleCount; ++j) {
10623c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        VkRectLayerKHR rect = region.pRectangles[j];
10624c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        // TODO: Need to update these errors to their unique error ids when available
10625c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if ((rect.offset.x + rect.extent.width) > swapchain_data->createInfo.imageExtent.width) {
106263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
106273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
106283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
106293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
106303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
106313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "chain, pRegion[%i].pRectangles[%i], the sum of offset.x "
106323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "(%i) and extent.width (%i) is greater than the "
106333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "corresponding swapchain's imageExtent.width (%i).",
106343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            i, j, rect.offset.x, rect.extent.width, swapchain_data->createInfo.imageExtent.width);
10635c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
10636c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if ((rect.offset.y + rect.extent.height) > swapchain_data->createInfo.imageExtent.height) {
106373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
106383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
106393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
106403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
106413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
106423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "chain, pRegion[%i].pRectangles[%i], the sum of offset.y "
106433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "(%i) and extent.height (%i) is greater than the "
106443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "corresponding swapchain's imageExtent.height (%i).",
106453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            i, j, rect.offset.y, rect.extent.height, swapchain_data->createInfo.imageExtent.height);
10646c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
10647c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if (rect.layer > swapchain_data->createInfo.imageArrayLayers) {
106483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |= log_msg(
10649c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10650c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
10651c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
10652c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, pRegion[%i].pRectangles[%i], the "
10653c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                "layer (%i) is greater than the corresponding swapchain's imageArrayLayers (%i).",
10654c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                i, j, rect.layer, swapchain_data->createInfo.imageArrayLayers);
10655c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
10656c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    }
10657c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                }
106585f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis            } else if (VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE == pnext->sType) {
106595f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                VkPresentTimesInfoGOOGLE *present_times_info = (VkPresentTimesInfoGOOGLE *)pnext;
106605f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                if (pPresentInfo->swapchainCount != present_times_info->swapchainCount) {
106615f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                    skip |=
106625f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
106635f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[0]), __LINE__,
106645f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis
106655f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                VALIDATION_ERROR_03214, "DS",
106665f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "vkQueuePresentKHR(): VkPresentTimesInfoGOOGLE.swapchainCount is %i but "
106675f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "pPresentInfo->swapchainCount is %i. For VkPresentTimesInfoGOOGLE down pNext "
106685f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "chain of VkPresentInfoKHR, VkPresentTimesInfoGOOGLE.swapchainCount "
106695f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "must equal VkPresentInfoKHR.swapchainCount.",
106705f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                present_times_info->swapchainCount, pPresentInfo->swapchainCount);
106715f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                }
10672c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            }
10673c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            pnext = (std_header *)pnext->pNext;
10674c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        }
10675c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis    }
106765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
106773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
106786c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
106796c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
106806c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
106814a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueuePresentKHR(queue, pPresentInfo);
106826c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
106836c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (result != VK_ERROR_VALIDATION_FAILED_EXT) {
106846c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // Semaphore waits occur before error generation, if the call reached
106856c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // the ICD. (Confirm?)
106866c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
106879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
106889867daedbf52debc77d6568162ee21e071699b80Chris Forbes            if (pSemaphore) {
106899867daedbf52debc77d6568162ee21e071699b80Chris Forbes                pSemaphore->signaler.first = VK_NULL_HANDLE;
106906c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes                pSemaphore->signaled = false;
106916c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes            }
106926c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        }
106939867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10694220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
10695220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Note: this is imperfect, in that we can get confused about what
10696220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // did or didn't succeed-- but if the app does that, it's confused
10697220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // itself just as much.
10698220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto local_result = pPresentInfo->pResults ? pPresentInfo->pResults[i] : result;
10699220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (local_result != VK_SUCCESS && local_result != VK_SUBOPTIMAL_KHR) continue;  // this present didn't actually happen.
10701220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10702220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Mark the image as having been released to the WSI
107039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10704220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
107059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_state = GetImageState(dev_data, image);
107061facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->acquired = false;
10707220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        }
10708220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
107099867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // Note: even though presentation is directed to a queue, there is no
107109867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // direct ordering between QP and subsequent work, so QP (and its
107119867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // semaphore waits) /never/ participate in any completion proof.
107126c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
107131344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
107145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
107155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
107165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10717c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic bool PreCallValidateCreateSharedSwapchainsKHR(layer_data *dev_data, uint32_t swapchainCount,
10718c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10719c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SURFACE_STATE *> &surface_state,
10720c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
107210342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (pCreateInfos) {
10722c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
107230342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
107249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            surface_state.push_back(GetSurfaceState(dev_data->instance_data, pCreateInfos[i].surface));
107259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            old_swapchain_state.push_back(GetSwapchainNode(dev_data, pCreateInfos[i].oldSwapchain));
107269ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            std::stringstream func_name;
107279ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            func_name << "vkCreateSharedSwapchainsKHR[" << swapchainCount << "]";
10728bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (PreCallValidateCreateSwapchainKHR(dev_data, func_name.str().c_str(), &pCreateInfos[i], surface_state[i],
10729bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  old_swapchain_state[i])) {
10730c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                return true;
107310342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            }
107320342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
107330342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10734c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return false;
10735c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
107360342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10737c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic void PostCallRecordCreateSharedSwapchainsKHR(layer_data *dev_data, VkResult result, uint32_t swapchainCount,
10738c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10739c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SURFACE_STATE *> &surface_state,
10740c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
107410342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (VK_SUCCESS == result) {
107420342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
107430342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(&pCreateInfos[i], pSwapchains[i]));
107440342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = swapchain_state.get();
107450342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            dev_data->device_extensions.swapchainMap[pSwapchains[i]] = std::move(swapchain_state);
107460342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
107470342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    } else {
107480342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
107490342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = nullptr;
107500342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
107510342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
107520342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    // Spec requires that even if CreateSharedSwapchainKHR fails, oldSwapchain behaves as replaced.
107530342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    for (uint32_t i = 0; i < swapchainCount; i++) {
107540342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        if (old_swapchain_state[i]) {
107550342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            old_swapchain_state[i]->replaced = true;
107560342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
107570342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        surface_state[i]->old_swapchain = old_swapchain_state[i];
107580342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10759c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return;
10760c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
10761c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10762c6cd632d064579a64e61d8704b411d0e4ace7adaMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
10763c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkSwapchainCreateInfoKHR *pCreateInfos,
10764c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
1076556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10766c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SURFACE_STATE *> surface_state;
10767c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SWAPCHAIN_NODE *> old_swapchain_state;
10768c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10769c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    if (PreCallValidateCreateSharedSwapchainsKHR(dev_data, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10770c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                 old_swapchain_state)) {
10771c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10772c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    }
10773c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10774c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    VkResult result =
10775c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        dev_data->dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
10776c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10777c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    PostCallRecordCreateSharedSwapchainsKHR(dev_data, result, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10778c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                            old_swapchain_state);
107790342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10780c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    return result;
10781c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young}
10782c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1078389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
1078489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
1078556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
107863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
107871344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
10788b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
10789449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
10790449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    if (fence == VK_NULL_HANDLE && semaphore == VK_NULL_HANDLE) {
107913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
107923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t &>(device), __LINE__, DRAWSTATE_SWAPCHAIN_NO_SYNC_FOR_ACQUIRE, "DS",
107933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: Semaphore and fence cannot both be VK_NULL_HANDLE. There would be no way "
107943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "to determine the completion of this operation.");
10795449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    }
10796449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
107979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
10798f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pSemaphore && pSemaphore->signaled) {
107993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
108003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<const uint64_t &>(semaphore), __LINE__, VALIDATION_ERROR_01952, "DS",
108013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state. %s",
108023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_01952]);
108035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10804f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
108059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
10806f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pFence) {
108073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateFenceForSubmit(dev_data, pFence);
108085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
108094a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes
108109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
10811fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
10812fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    if (swapchain_data->replaced) {
108133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
108143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_REPLACED, "DS",
108153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: This swapchain has been replaced. The application can still "
108163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "present any images it has acquired, but cannot acquire any more.");
10817fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    }
10818fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
108199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
108204a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState != UNCALLED) {
108216569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        uint64_t acquired_images = std::count_if(swapchain_data->images.begin(), swapchain_data->images.end(),
108229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                 [=](VkImage image) { return GetImageState(dev_data, image)->acquired; });
108234a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        if (acquired_images > swapchain_data->images.size() - physical_device_state->surfaceCapabilities.minImageCount) {
108243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
108256569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
108266569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        reinterpret_cast<uint64_t const &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_TOO_MANY_IMAGES, "DS",
108276569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        "vkAcquireNextImageKHR: Application has already acquired the maximum number of images (0x%" PRIxLEAST64 ")",
108286569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        acquired_images);
108294a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        }
108304a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    }
1083175269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
1083275269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    if (swapchain_data->images.size() == 0) {
108333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
108343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        reinterpret_cast<uint64_t const &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_IMAGES_NOT_FOUND, "DS",
108353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: No images found to acquire from. Application probably did not call "
108363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkGetSwapchainImagesKHR after swapchain creation.");
1083775269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    }
1083875269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
10839b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
108401344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
108413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
10842f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
108434a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
10844f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
10845f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.lock();
10846f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
10847f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pFence) {
10848f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pFence->state = FENCE_INFLIGHT;
10849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            pFence->signaler.first = VK_NULL_HANDLE;  // ANI isn't on a queue, so this can't participate in a completion proof.
10850f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
10851f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
10852f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        // A successful call to AcquireNextImageKHR counts as a signal operation on semaphore
10853f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pSemaphore) {
10854f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pSemaphore->signaled = true;
108559867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pSemaphore->signaler.first = VK_NULL_HANDLE;
10856f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
10857220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10858220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        // Mark the image as acquired.
10859220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        auto image = swapchain_data->images[*pImageIndex];
108609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, image);
108611facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->acquired = true;
108625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10863f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.unlock();
108641344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
108655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
108665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
108675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10868f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
10869f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski                                                        VkPhysicalDevice *pPhysicalDevices) {
108703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1087156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
10872bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    assert(instance_data);
10873219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
10874bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    // For this instance, flag when vkEnumeratePhysicalDevices goes to QUERY_COUNT and then QUERY_DETAILS
10875bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
10876bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_COUNT;
10877f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    } else {
10878bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        if (UNCALLED == instance_data->vkEnumeratePhysicalDevicesState) {
10879bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Flag warning here. You can call this without having queried the count, but it may not be
10880bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // robust on platforms with multiple physical devices.
108813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
108823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
108833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call sequence has vkEnumeratePhysicalDevices() w/ non-NULL pPhysicalDevices. You should first "
108843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "call vkEnumeratePhysicalDevices() w/ NULL pPhysicalDevices to query pPhysicalDeviceCount.");
10885cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }  // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
10886bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        else if (instance_data->physical_devices_count != *pPhysicalDeviceCount) {
10887bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Having actual count match count from app is not a requirement, so this can be a warning
108883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
108893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
108903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call to vkEnumeratePhysicalDevices() w/ pPhysicalDeviceCount value %u, but actual count "
108913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "supported by this instance is %u.",
108923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            *pPhysicalDeviceCount, instance_data->physical_devices_count);
10893bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
10894bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_DETAILS;
10895f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
108963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
10897bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
10898bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
10899bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    VkResult result = instance_data->dispatch_table.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
10900bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
10901bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->physical_devices_count = *pPhysicalDeviceCount;
10902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (result == VK_SUCCESS) {  // Save physical devices
10903bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
10904bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            auto &phys_device_state = instance_data->physical_device_map[pPhysicalDevices[i]];
10905bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            phys_device_state.phys_device = pPhysicalDevices[i];
10906bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Init actual features for each physical device
10907bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            instance_data->dispatch_table.GetPhysicalDeviceFeatures(pPhysicalDevices[i], &phys_device_state.features);
10908bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
10909bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
10910bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    return result;
10911f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
10912f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
1091343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to handle validation for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1091443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
1091543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 PHYSICAL_DEVICE_STATE *pd_state,
1091643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 uint32_t *pQueueFamilyPropertyCount, bool qfp_null,
1091743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 const char *count_var_name, const char *caller_name) {
1091843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = false;
1091943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (qfp_null) {
1092043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_COUNT;
1092143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } else {
1092243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // Verify that for each physical device, this function is called first with NULL pQueueFamilyProperties ptr in order to get
1092343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // count
1092443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
1092543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
1092643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
1092743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "Call sequence has %s() w/ non-NULL "
1092843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "pQueueFamilyProperties. You should first call %s() w/ "
1092943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "NULL pQueueFamilyProperties to query pCount.",
1093043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            caller_name, caller_name);
1093143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1093243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // Then verify that pCount that is passed in on second call matches what was returned
1093343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (pd_state->queueFamilyPropertiesCount != *pQueueFamilyPropertyCount) {
1093443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            // TODO: this is not a requirement of the Valid Usage section for vkGetPhysicalDeviceQueueFamilyProperties, so
1093543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            // provide as warning
1093643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
1093743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
1093843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "Call to %s() w/ %s value %u, but actual count supported by this physicalDevice is %u.", caller_name,
1093943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            count_var_name, *pQueueFamilyPropertyCount, pd_state->queueFamilyPropertiesCount);
1094043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1094143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_DETAILS;
1094243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1094343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return skip;
1094443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1094543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1094643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
1094743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                  PHYSICAL_DEVICE_STATE *pd_state, uint32_t *pCount,
1094843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
1094943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, pCount,
1095043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                (nullptr == pQueueFamilyProperties), "pCount",
1095143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties()");
1095243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1095343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1095443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_layer_data *instance_data,
1095543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      PHYSICAL_DEVICE_STATE *pd_state,
1095643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1095743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1095843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, pQueueFamilyPropertyCount,
1095943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                (nullptr == pQueueFamilyProperties), "pQueueFamilyPropertyCount",
1096043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties2KHR()");
1096143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1096243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1096343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to update state for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1096443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1096543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                    VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1096643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (!pQueueFamilyProperties) {
1096743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->queueFamilyPropertiesCount = count;
1096843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } else {  // Save queue family properties
1096943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (pd_state->queue_family_properties.size() < count) pd_state->queue_family_properties.resize(count);
1097043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        for (uint32_t i = 0; i < count; i++) {
1097143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            pd_state->queue_family_properties[i] = pQueueFamilyProperties[i].queueFamilyProperties;
1097243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1097343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1097443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1097543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1097643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1097743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 VkQueueFamilyProperties *pQueueFamilyProperties) {
1097843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    VkQueueFamilyProperties2KHR *pqfp = nullptr;
1097943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    std::vector<VkQueueFamilyProperties2KHR> qfp;
1098043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    qfp.resize(count);
1098143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (pQueueFamilyProperties) {
1098243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        for (uint32_t i = 0; i < count; ++i) {
1098343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
1098443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].pNext = nullptr;
1098543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].queueFamilyProperties = pQueueFamilyProperties[i];
1098643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1098743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pqfp = qfp.data();
1098843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1098943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pqfp);
1099043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1099143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1099243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1099343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                     VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1099443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pQueueFamilyProperties);
1099543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1099643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
10997bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
10998bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
1099956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
110009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1100143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
1100243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip =
1100343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_data, physical_device_state, pCount, pQueueFamilyProperties);
1100443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (skip) {
1100543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        return;
1100643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1100743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pCount, pQueueFamilyProperties);
1100843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    PostCallRecordGetPhysicalDeviceQueueFamilyProperties(physical_device_state, *pCount, pQueueFamilyProperties);
1100943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1101043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1101143947a6175e3e942e04d902f4d18928168e2d0dbTobin EhlisVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
1101243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1101343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1101456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
110159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1101643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
1101743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_data, physical_device_state,
1101843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                          pQueueFamilyPropertyCount, pQueueFamilyProperties);
1101943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (skip) {
1102043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        return;
11021cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski    }
1102243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount,
1102343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                             pQueueFamilyProperties);
1102443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(physical_device_state, *pQueueFamilyPropertyCount,
1102543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                             pQueueFamilyProperties);
11026cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski}
11027cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski
11028bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskitemplate <typename TCreateInfo, typename FPtr>
11029bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkResult CreateSurface(VkInstance instance, TCreateInfo const *pCreateInfo, VkAllocationCallbacks const *pAllocator,
11030bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                              VkSurfaceKHR *pSurface, FPtr fptr) {
1103156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11032747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11033747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    // Call down the call chain:
11034747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    VkResult result = (instance_data->dispatch_table.*fptr)(instance, pCreateInfo, pAllocator, pSurface);
11035747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11036747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (result == VK_SUCCESS) {
11037747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        std::unique_lock<std::mutex> lock(global_lock);
11038747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map[*pSurface] = SURFACE_STATE(*pSurface);
11039747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        lock.unlock();
11040747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11041747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11042747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return result;
11043747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11044747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11045747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {
110463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1104756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11048747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
110499a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
11050747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11051747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (surface_state) {
11052747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // TODO: track swapchains created from this surface.
11053747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map.erase(surface);
11054747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11055747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    lock.unlock();
11056747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
110573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
11058747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // Call down the call chain:
11059747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->dispatch_table.DestroySurfaceKHR(instance, surface, pAllocator);
11060747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11061747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11062747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
110636f2ed666809272002a31b3b4f8adf6581cb41819Norbert NopperVKAPI_ATTR VkResult VKAPI_CALL CreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
110646f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper                                                            const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
110656f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateDisplayPlaneSurfaceKHR);
110666f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper}
110676f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper
11068747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
11069747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo,
11070747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11071747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateAndroidSurfaceKHR);
11072747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
11074747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11075747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
11076747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateMirSurfaceKHR(VkInstance instance, const VkMirSurfaceCreateInfoKHR *pCreateInfo,
11077747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11078747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateMirSurfaceKHR);
11079747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11080cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
11081747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11082747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
11083747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
11084747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11085a9c6cc532ce0ef61d48d1419a96aae51b0e4c64aTobin Ehlis    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWaylandSurfaceKHR);
11086747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11087cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
11088747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11089747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
11090747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
11091747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11092747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWin32SurfaceKHR);
11093747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11094cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
11095747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11096747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
11097747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
11098747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11099747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXcbSurfaceKHR);
11100747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
11102747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11103747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
11104747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
11105bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11106747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXlibSurfaceKHR);
11107747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11108cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
11109747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
1111040921785005eb449ec7c18229f0d84c879708b8aChris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
1111140921785005eb449ec7c18229f0d84c879708b8aChris Forbes                                                                       VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
1111256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1111340921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1111440921785005eb449ec7c18229f0d84c879708b8aChris Forbes    std::unique_lock<std::mutex> lock(global_lock);
111159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1111640921785005eb449ec7c18229f0d84c879708b8aChris Forbes    lock.unlock();
1111740921785005eb449ec7c18229f0d84c879708b8aChris Forbes
11118bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11119bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
1112040921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1112140921785005eb449ec7c18229f0d84c879708b8aChris Forbes    if (result == VK_SUCCESS) {
1112240921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
1112340921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->surfaceCapabilities = *pSurfaceCapabilities;
1112440921785005eb449ec7c18229f0d84c879708b8aChris Forbes    }
1112540921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1112640921785005eb449ec7c18229f0d84c879708b8aChris Forbes    return result;
1112740921785005eb449ec7c18229f0d84c879708b8aChris Forbes}
1112840921785005eb449ec7c18229f0d84c879708b8aChris Forbes
11129418a8711f3301f3027a900bb45daaf0892f4e644Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
11130418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes                                                                  VkSurfaceKHR surface, VkBool32 *pSupported) {
1113156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11132418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
111339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
11134418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    lock.unlock();
11135418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11136bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11137bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
11138418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11139418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    if (result == VK_SUCCESS) {
111406569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        surface_state->gpu_queue_support[{physicalDevice, queueFamilyIndex}] = (*pSupported != 0);
11141418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    }
11142418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11143418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    return result;
11144418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes}
11145418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
111469e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
111479e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       uint32_t *pPresentModeCount,
111489e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       VkPresentModeKHR *pPresentModes) {
111493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1115056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
111519e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
111529e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    // TODO: this isn't quite right. available modes may differ by surface AND physical device.
111539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11154bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState;
111559e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
111569e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (pPresentModes) {
111579e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        // Compare the preliminary value of *pPresentModeCount with the value this time:
11158bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_mode_count = (uint32_t)physical_device_state->present_modes.size();
111599e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        switch (call_state) {
11160cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
111613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
11162bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
11163cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11164cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with non-NULL pPresentModeCount; but no prior positive "
11165cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pPresentModeCount.");
11166cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11167cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11168cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // both query count and query details
11169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (*pPresentModeCount != prev_mode_count) {
111703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
111713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, reinterpret_cast<uint64_t>(physicalDevice),
111723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
111733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with *pPresentModeCount (%u) that "
111743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "differs from the value "
111753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "(%u) that was returned when pPresentModes was NULL.",
111763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    *pPresentModeCount, prev_mode_count);
11177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
111799e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
111809e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
111819e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    lock.unlock();
111829e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
111833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
111849e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11185bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount,
11186bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                        pPresentModes);
111879e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
111889e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
111899e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        lock.lock();
111909e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
111919e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (*pPresentModeCount) {
11192cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
111939e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (*pPresentModeCount > physical_device_state->present_modes.size())
111949e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes.resize(*pPresentModeCount);
111959e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
111969e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pPresentModes) {
11197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
111989e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            for (uint32_t i = 0; i < *pPresentModeCount; i++) {
111999e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes[i] = pPresentModes[i];
112009e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            }
112019e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112025faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
112035faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112045faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    return result;
112055faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes}
112065faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112075faa662f6859b01c72d79027abde363d5f10dcd7Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
112085faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  uint32_t *pSurfaceFormatCount,
112095faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  VkSurfaceFormatKHR *pSurfaceFormats) {
112103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1121156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
112125faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
112139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11214bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState;
112155faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112165faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (pSurfaceFormats) {
11217bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_format_count = (uint32_t)physical_device_state->surface_formats.size();
112185faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112195faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        switch (call_state) {
11220cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
11221cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Since we haven't recorded a preliminary value of *pSurfaceFormatCount, that likely means that the application
11222cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // didn't
11223cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // previously call this function with a NULL value of pSurfaceFormats:
112243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
11225bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
11226cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11227cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount; but no prior positive "
11228cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pSurfaceFormats.");
11229cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11230cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11231cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (prev_format_count != *pSurfaceFormatCount) {
112323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
11233cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
11234cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, reinterpret_cast<uint64_t>(physicalDevice), __LINE__,
11235cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        DEVLIMITS_COUNT_MISMATCH, "DL",
11236cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount, and with pSurfaceFormats "
11237cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "set "
11238cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "to "
11239cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "a value (%u) that is greater than the value (%u) that was returned when pSurfaceFormatCount was NULL.",
11240cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        *pSurfaceFormatCount, prev_format_count);
11241cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11242cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
112439e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112449e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
112455faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    lock.unlock();
112465faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
112489e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112495faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    // Call down the call chain:
112505faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount,
112515faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                                   pSurfaceFormats);
112525faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112535faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
112545faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        lock.lock();
112555faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112565faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (*pSurfaceFormatCount) {
11257cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
112585faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (*pSurfaceFormatCount > physical_device_state->surface_formats.size())
112595faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats.resize(*pSurfaceFormatCount);
112605faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
112615faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (pSurfaceFormats) {
11262cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
112635faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
112645faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats[i] = pSurfaceFormats[i];
112655faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
112665faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
112675faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
112689e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    return result;
112699e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes}
112709e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11271bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
11272bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
11273bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkAllocationCallbacks *pAllocator,
11274bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            VkDebugReportCallbackEXT *pMsgCallback) {
1127556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
112769172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkResult res = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
112775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == res) {
11278b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
112798860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        res = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
112805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
112815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
112825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
112835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11284bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
1128589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                         const VkAllocationCallbacks *pAllocator) {
1128656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
112879172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
11288b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
112898860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_destroy_msg_callback(instance_data->report_data, msgCallback, pAllocator);
112905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
112915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11292bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
11293bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
11294bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1129556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
112969172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
112975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
112985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11299bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
11300a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11301a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11302a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11303bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11304bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkLayerProperties *pProperties) {
11305a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11306a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11307a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11308bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
11309bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                    VkExtensionProperties *pProperties) {
11310a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
11311a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
11312a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11313a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return VK_ERROR_LAYER_NOT_PRESENT;
11314a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11315a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11316bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
11317bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
11318cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
11319a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
11320a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    assert(physicalDevice);
11321a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
1132256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
113239172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
1132408939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1132508939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11326582b6ed09649188d55ed3b6237352caf9f3384a9Mike WeiblenVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDeviceGroupsKHX(
11327582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupPropertiesKHX *pPhysicalDeviceGroupProperties) {
113283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
11329582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11330582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen
11331582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    if (instance_data) {
11332582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        // For this instance, flag when EnumeratePhysicalDeviceGroupsKHX goes to QUERY_COUNT and then QUERY_DETAILS.
11333582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        if (NULL == pPhysicalDeviceGroupProperties) {
11334582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_COUNT;
11335582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        } else {
11336582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            if (UNCALLED == instance_data->vkEnumeratePhysicalDeviceGroupsState) {
11337582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // Flag warning here. You can call this without having queried the count, but it may not be
11338582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // robust on platforms with multiple physical devices.
113393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
113403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
113413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "Call sequence has vkEnumeratePhysicalDeviceGroupsKHX() w/ non-NULL "
113423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "pPhysicalDeviceGroupProperties. You should first "
113433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "call vkEnumeratePhysicalDeviceGroupsKHX() w/ NULL pPhysicalDeviceGroupProperties to query "
113443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "pPhysicalDeviceGroupCount.");
11345582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            } // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
11346582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            else if (instance_data->physical_device_groups_count != *pPhysicalDeviceGroupCount) {
11347582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // Having actual count match count from app is not a requirement, so this can be a warning
113483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
11349582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
113503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
113513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call to vkEnumeratePhysicalDeviceGroupsKHX() w/ pPhysicalDeviceGroupCount value %u, but actual count "
113523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "supported by this instance is %u.",
113533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            *pPhysicalDeviceGroupCount, instance_data->physical_device_groups_count);
11354582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            }
11355582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_DETAILS;
11356582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
113573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        if (skip) {
11358582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            return VK_ERROR_VALIDATION_FAILED_EXT;
11359582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
11360582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        VkResult result = instance_data->dispatch_table.EnumeratePhysicalDeviceGroupsKHX(instance, pPhysicalDeviceGroupCount,
11361582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            pPhysicalDeviceGroupProperties);
11362582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        if (NULL == pPhysicalDeviceGroupProperties) {
11363582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->physical_device_groups_count = *pPhysicalDeviceGroupCount;
11364582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        } else if (result == VK_SUCCESS) { // Save physical devices
11365582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
11366582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                for (uint32_t j = 0; j < pPhysicalDeviceGroupProperties[i].physicalDeviceCount; j++) {
11367582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    VkPhysicalDevice cur_phys_dev = pPhysicalDeviceGroupProperties[i].physicalDevices[j];
11368582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    auto &phys_device_state = instance_data->physical_device_map[cur_phys_dev];
11369582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    phys_device_state.phys_device = cur_phys_dev;
11370582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    // Init actual features for each physical device
11371582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    instance_data->dispatch_table.GetPhysicalDeviceFeatures(cur_phys_dev, &phys_device_state.features);
11372582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                }
11373582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            }
11374582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
11375582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        return result;
11376582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    } else {
11377582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__,
11378582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            DEVLIMITS_INVALID_INSTANCE, "DL",
11379582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            "Invalid instance (0x%" PRIxLEAST64 ") passed into vkEnumeratePhysicalDeviceGroupsKHX().", (uint64_t)instance);
11380582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    }
11381582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    return VK_ERROR_VALIDATION_FAILED_EXT;
11382582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen}
11383582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen
113846246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorUpdateTemplateKHR(VkDevice device,
113856246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
113866246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 const VkAllocationCallbacks *pAllocator,
113876246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
113886246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
11389a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski    VkResult result =
11390a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski        dev_data->dispatch_table.CreateDescriptorUpdateTemplateKHR(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
113916246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    if (VK_SUCCESS == result) {
113926246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
113936246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        // Shadow template createInfo for later updates
11394a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski        safe_VkDescriptorUpdateTemplateCreateInfoKHR *local_create_info =
11395a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski            new safe_VkDescriptorUpdateTemplateCreateInfoKHR(pCreateInfo);
113966246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info));
113976246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        dev_data->desc_template_map[*pDescriptorUpdateTemplate] = std::move(template_state);
113986246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    }
113996246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    return result;
114006246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
114016246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
114026246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplateKHR(VkDevice device,
114036246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
114046246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              const VkAllocationCallbacks *pAllocator) {
114056246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
114066246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
114076246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->desc_template_map.erase(descriptorUpdateTemplate);
114086246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    lock.unlock();
114096246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);
114106246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
114116246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
1141225f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSetsWithTemplate()
1141325f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinskistatic void PostCallRecordUpdateDescriptorSetWithTemplateKHR(layer_data *device_data, VkDescriptorSet descriptorSet,
1141425f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski                                                             VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
1141525f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski                                                             const void *pData) {
1141667fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    auto const template_map_entry = device_data->desc_template_map.find(descriptorUpdateTemplate);
1141767fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    if (template_map_entry == device_data->desc_template_map.end()) {
1141867fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski        assert(0);
1141967fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    }
1142067fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
1142125f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski    cvdescriptorset::PerformUpdateDescriptorSetsWithTemplateKHR(device_data, descriptorSet, template_map_entry->second, pData);
1142267fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski}
1142367fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
114246246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
114256246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
114266246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              const void *pData) {
1142767fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1142867fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    device_data->dispatch_table.UpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, pData);
1142967fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
1143067fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    PostCallRecordUpdateDescriptorSetWithTemplateKHR(device_data, descriptorSet, descriptorUpdateTemplate, pData);
114316246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
114326246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
114336246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
114346246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                               VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
114356246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                               VkPipelineLayout layout, uint32_t set, const void *pData) {
114366246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
114376246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set, pData);
114386246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
114396246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
11440bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_instance_command(const char *name);
114417ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
11442bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_device_command(const char *name);
1144380be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
114446246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinskistatic PFN_vkVoidFunction intercept_device_extension_command(const char *name, VkDevice device);
114456246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
11446bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_swapchain_command(const char *name, VkDevice dev);
1144709a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
11448bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_surface_command(const char *name, VkInstance instance);
11449747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11450582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblenstatic PFN_vkVoidFunction
11451582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblenintercept_extension_instance_commands(const char *name, VkInstance instance);
11452b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
1145389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice dev, const char *funcName) {
1145480be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    assert(dev);
114555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
114566246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    PFN_vkVoidFunction proc = intercept_core_device_command(funcName);
114576246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    if (!proc) proc = intercept_device_extension_command(funcName, dev);
114586246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    if (!proc) proc = intercept_khr_swapchain_command(funcName, dev);
11459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
1146009a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1146156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(dev), layer_data_map);
114624a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = dev_data->dispatch_table;
11463cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetDeviceProcAddr) return nullptr;
114644a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetDeviceProcAddr(dev, funcName);
114655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1146789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
114687ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    PFN_vkVoidFunction proc = intercept_core_instance_command(funcName);
11469cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_core_device_command(funcName);
11470cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_khr_swapchain_command(funcName, VK_NULL_HANDLE);
11471cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_khr_surface_command(funcName, instance);
11472cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
114735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
114747ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    assert(instance);
114755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1147656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
114778860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    proc = debug_report_get_instance_proc_addr(instance_data->report_data, funcName);
11478cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
114795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11480b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    proc = intercept_extension_instance_commands(funcName, instance);
11481cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
11482b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
114834a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = instance_data->dispatch_table;
11484cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetInstanceProcAddr) return nullptr;
114854a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetInstanceProcAddr(instance, funcName);
114865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1148708939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11488b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
11489b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(instance);
11490b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
1149156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11492b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11493b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    auto &table = instance_data->dispatch_table;
11494cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetPhysicalDeviceProcAddr) return nullptr;
11495b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return table.GetPhysicalDeviceProcAddr(instance, funcName);
11496b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11497b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11498bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_instance_command(const char *name) {
114997ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    static const struct {
115007ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu        const char *name;
115017ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu        PFN_vkVoidFunction proc;
115027ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    } core_instance_commands[] = {
11503bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr)},
11504bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vk_layerGetPhysicalDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProcAddr)},
11505bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)},
11506bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance)},
11507bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice)},
11508bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices)},
11509bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties)},
11510bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
11511bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties)},
11512bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties)},
11513bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties)},
11514bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties)},
115157ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    };
115167ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
115177ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++) {
11518cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(core_instance_commands[i].name, name)) return core_instance_commands[i].proc;
115197ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    }
115207ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
115217ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    return nullptr;
115227ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu}
115237ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
11524bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_device_command(const char *name) {
1152580be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    static const struct {
1152680be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu        const char *name;
1152780be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu        PFN_vkVoidFunction proc;
1152880be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    } core_device_commands[] = {
11529593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)},
11530593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueSubmit", reinterpret_cast<PFN_vkVoidFunction>(QueueSubmit)},
11531593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences)},
11532593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(GetFenceStatus)},
11533593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(QueueWaitIdle)},
11534593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDeviceWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(DeviceWaitIdle)},
11535593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue)},
11536593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
11537593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice)},
11538593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(DestroyFence)},
11539593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences)},
11540593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(DestroySemaphore)},
11541593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(DestroyEvent)},
11542593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyQueryPool)},
11543593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyBuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyBuffer)},
11544593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyBufferView", reinterpret_cast<PFN_vkVoidFunction>(DestroyBufferView)},
11545593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyImage", reinterpret_cast<PFN_vkVoidFunction>(DestroyImage)},
11546593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyImageView", reinterpret_cast<PFN_vkVoidFunction>(DestroyImageView)},
11547593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(DestroyShaderModule)},
11548593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipeline", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipeline)},
11549593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineLayout)},
11550593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(DestroySampler)},
11551593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorSetLayout)},
11552593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorPool)},
11553593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyFramebuffer)},
11554593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(DestroyRenderPass)},
11555593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateBuffer)},
11556593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateBufferView", reinterpret_cast<PFN_vkVoidFunction>(CreateBufferView)},
11557593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateImage", reinterpret_cast<PFN_vkVoidFunction>(CreateImage)},
11558593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateImageView", reinterpret_cast<PFN_vkVoidFunction>(CreateImageView)},
11559593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(CreateFence)},
11560593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreatePipelineCache", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineCache)},
11561593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipelineCache", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineCache)},
11562593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData)},
11563593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkMergePipelineCaches", reinterpret_cast<PFN_vkVoidFunction>(MergePipelineCaches)},
11564593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateGraphicsPipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateGraphicsPipelines)},
11565593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateComputePipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateComputePipelines)},
11566593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler)},
11567593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorSetLayout)},
11568593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineLayout)},
11569593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorPool)},
11570593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(ResetDescriptorPool)},
11571593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(AllocateDescriptorSets)},
11572593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets)},
11573593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets)},
11574593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateCommandPool", reinterpret_cast<PFN_vkVoidFunction>(CreateCommandPool)},
11575593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyCommandPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyCommandPool)},
11576593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetCommandPool", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandPool)},
11577593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool)},
11578593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers)},
11579593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(FreeCommandBuffers)},
11580593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(BeginCommandBuffer)},
11581593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkEndCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(EndCommandBuffer)},
11582593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandBuffer)},
11583593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(CmdBindPipeline)},
11584593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetViewport", reinterpret_cast<PFN_vkVoidFunction>(CmdSetViewport)},
11585593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(CmdSetScissor)},
11586593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(CmdSetLineWidth)},
11587593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBias)},
11588593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdSetBlendConstants)},
11589593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBounds)},
11590593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilCompareMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilCompareMask)},
11591593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilWriteMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilWriteMask)},
11592593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilReference", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilReference)},
11593593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets)},
11594593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindVertexBuffers", reinterpret_cast<PFN_vkVoidFunction>(CmdBindVertexBuffers)},
11595593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdBindIndexBuffer)},
11596593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw)},
11597593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed)},
11598593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirect)},
11599593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirect)},
11600593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatch)},
11601593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchIndirect)},
11602593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBuffer)},
11603593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImage)},
11604593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBlitImage", reinterpret_cast<PFN_vkVoidFunction>(CmdBlitImage)},
11605593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyBufferToImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBufferToImage)},
11606593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer)},
11607593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdUpdateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdUpdateBuffer)},
11608593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdFillBuffer)},
11609593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearColorImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearColorImage)},
11610593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearDepthStencilImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearDepthStencilImage)},
11611593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearAttachments", reinterpret_cast<PFN_vkVoidFunction>(CmdClearAttachments)},
11612593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResolveImage", reinterpret_cast<PFN_vkVoidFunction>(CmdResolveImage)},
11613b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        {"vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(GetImageSubresourceLayout) },
11614593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdSetEvent)},
11615593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdResetEvent)},
11616593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdWaitEvents", reinterpret_cast<PFN_vkVoidFunction>(CmdWaitEvents)},
11617593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier)},
11618593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery)},
11619593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdEndQuery)},
11620593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CmdResetQueryPool)},
11621593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyQueryPoolResults)},
11622593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdPushConstants)},
11623593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdWriteTimestamp", reinterpret_cast<PFN_vkVoidFunction>(CmdWriteTimestamp)},
11624593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateFramebuffer)},
11625593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(CreateShaderModule)},
11626593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass)},
11627593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass)},
11628593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass)},
11629593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass)},
11630593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(CmdExecuteCommands)},
11631593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent)},
11632593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(MapMemory)},
11633593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory)},
11634593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(FlushMappedMemoryRanges)},
11635593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(InvalidateMappedMemoryRanges)},
11636593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(AllocateMemory)},
11637593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory)},
11638593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory)},
11639593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements)},
11640593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements)},
11641593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults)},
11642593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory)},
11643593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueBindSparse", reinterpret_cast<PFN_vkVoidFunction>(QueueBindSparse)},
11644593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore)},
11645593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(CreateEvent)},
1164680be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    };
1164780be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1164880be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(core_device_commands); i++) {
11649cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(core_device_commands[i].name, name)) return core_device_commands[i].proc;
116506246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    }
116516246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
116526246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    return nullptr;
116536246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
116546246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
116556246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinskistatic PFN_vkVoidFunction intercept_device_extension_command(const char *name, VkDevice device) {
116566246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
116576246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
116586246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    const struct {
116596246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        const char *name;
116606246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        PFN_vkVoidFunction proc;
116616246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        bool enabled;
116626246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    } device_extension_commands[] = {
116636246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        {"vkCreateDescriptorUpdateTemplateKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorUpdateTemplateKHR),
116646246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski         device_data->device_extensions.khr_descriptor_update_template_enabled},
116656246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        {"vkDestroyDescriptorUpdateTemplateKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorUpdateTemplateKHR),
116666246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski         device_data->device_extensions.khr_descriptor_update_template_enabled},
116676246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        {"vkUpdateDescriptorSetWithTemplateKHR", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSetWithTemplateKHR),
116686246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski         device_data->device_extensions.khr_descriptor_update_template_enabled},
116696246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        {"vkCmdPushDescriptorSetWithTemplateKHR", reinterpret_cast<PFN_vkVoidFunction>(CmdPushDescriptorSetWithTemplateKHR),
116706246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski         device_data->device_extensions.khr_descriptor_update_template_enabled},
116716246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    };
116726246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
116736246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    if (!device_data || !device_data->device_extensions.khr_descriptor_update_template_enabled) return nullptr;
116746246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
116756246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    for (size_t i = 0; i < ARRAY_SIZE(device_extension_commands); i++) {
116766246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        if (!strcmp(device_extension_commands[i].name, name) && device_extension_commands[i].enabled)
116776246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski            return device_extension_commands[i].proc;
1167880be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    }
1167980be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1168080be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    return nullptr;
1168180be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu}
1168280be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
11683bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_swapchain_command(const char *name, VkDevice dev) {
1168409a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    static const struct {
1168509a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu        const char *name;
1168609a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu        PFN_vkVoidFunction proc;
1168709a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    } khr_swapchain_commands[] = {
11688bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR)},
11689bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR)},
11690bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR)},
11691bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR)},
11692bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkQueuePresentKHR", reinterpret_cast<PFN_vkVoidFunction>(QueuePresentKHR)},
1169309a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    };
11694c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    layer_data *dev_data = nullptr;
1169509a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
116963f6f8132355ebdae2736b31fc20de2ac60a70310Chia-I Wu    if (dev) {
1169756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        dev_data = GetLayerDataPtr(get_dispatch_key(dev), layer_data_map);
11698599899dabe438a8ea144c0add628d3f5afe54dd0Chris Forbes        if (!dev_data->device_extensions.khr_swapchain_enabled) return nullptr;
116993f6f8132355ebdae2736b31fc20de2ac60a70310Chia-I Wu    }
1170009a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1170109a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(khr_swapchain_commands); i++) {
11702cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(khr_swapchain_commands[i].name, name)) return khr_swapchain_commands[i].proc;
1170309a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    }
1170409a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
11705c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    if (dev_data) {
11706599899dabe438a8ea144c0add628d3f5afe54dd0Chris Forbes        if (!dev_data->device_extensions.khr_display_swapchain_enabled) return nullptr;
11707c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    }
11708c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
11709cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!strcmp("vkCreateSharedSwapchainsKHR", name)) return reinterpret_cast<PFN_vkVoidFunction>(CreateSharedSwapchainsKHR);
11710c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1171109a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    return nullptr;
11712747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11713747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11714bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_surface_command(const char *name, VkInstance instance) {
11715747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    static const struct {
11716747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        const char *name;
11717747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        PFN_vkVoidFunction proc;
11718747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        bool instance_layer_data::*enable;
11719747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    } khr_surface_commands[] = {
11720747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
11721747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateAndroidSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateAndroidSurfaceKHR),
11722bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::androidSurfaceExtensionEnabled},
11723cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
11724747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
11725747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateMirSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateMirSurfaceKHR),
11726bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::mirSurfaceExtensionEnabled},
11727cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
11728747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
11729747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateWaylandSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWaylandSurfaceKHR),
11730bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::waylandSurfaceExtensionEnabled},
11731cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
11732747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
11733747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateWin32SurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWin32SurfaceKHR),
11734bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::win32SurfaceExtensionEnabled},
11735cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
11736747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
11737747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateXcbSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXcbSurfaceKHR),
11738bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::xcbSurfaceExtensionEnabled},
11739cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
11740747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
11741747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateXlibSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXlibSurfaceKHR),
11742bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::xlibSurfaceExtensionEnabled},
11743cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
11744bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateDisplayPlaneSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateDisplayPlaneSurfaceKHR),
11745bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::displayExtensionEnabled},
11746747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkDestroySurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySurfaceKHR),
11747bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
1174840921785005eb449ec7c18229f0d84c879708b8aChris Forbes        {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceCapabilitiesKHR),
11749bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
11750418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes        {"vkGetPhysicalDeviceSurfaceSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceSupportKHR),
11751bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
117529e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        {"vkGetPhysicalDeviceSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfacePresentModesKHR),
11753bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
117545faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        {"vkGetPhysicalDeviceSurfaceFormatsKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormatsKHR),
11755bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
11756747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    };
11757747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11758747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    instance_layer_data *instance_data = nullptr;
11759747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (instance) {
1176056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11761747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11762747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11763747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    for (size_t i = 0; i < ARRAY_SIZE(khr_surface_commands); i++) {
11764747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(khr_surface_commands[i].name, name)) {
11765cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (instance_data && !(instance_data->*(khr_surface_commands[i].enable))) return nullptr;
11766747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            return khr_surface_commands[i].proc;
11767747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        }
11768747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11769747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11770747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return nullptr;
1177109a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu}
1177209a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1177343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic PFN_vkVoidFunction intercept_extension_instance_commands(const char *name, VkInstance instance) {
1177443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    static const struct {
1177543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        const char *name;
1177643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        PFN_vkVoidFunction proc;
1177743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        bool instance_layer_data::*enable;
1177843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } instance_extension_commands[] = {
1177943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        {"vkGetPhysicalDeviceQueueFamilyProperties2KHR",
1178043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis         reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties2KHR)},
11781582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        {"vkEnumeratePhysicalDeviceGroupsKHX",
11782582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen         reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDeviceGroupsKHX)},
1178343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    };
1178443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1178543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    for (size_t i = 0; i < ARRAY_SIZE(instance_extension_commands); i++) {
1178643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (!strcmp(instance_extension_commands[i].name, name)) {
1178743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            return instance_extension_commands[i].proc;
1178843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1178943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1179043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return nullptr;
1179143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
11792b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11793cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski}  // namespace core_validation
11794d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11795d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu// vk_layer_logging.h expects these to be defined
11796d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11797bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance,
11798bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
11799bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkAllocationCallbacks *pAllocator,
11800bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkDebugReportCallbackEXT *pMsgCallback) {
1180189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
11802d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11803d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11804bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
11805bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                           const VkAllocationCallbacks *pAllocator) {
1180689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
11807d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11808d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11809bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
11810bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
11811bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1181289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
11813d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11814d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11815a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu// loader-layer interface v0, just wrappers since there is only a layer
11816d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11817bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
11818bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                      VkExtensionProperties *pProperties) {
11819a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
1182008939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1182108939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11822bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
11823bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                  VkLayerProperties *pProperties) {
11824a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceLayerProperties(pCount, pProperties);
1182508939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1182608939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11827bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11828bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                VkLayerProperties *pProperties) {
11829a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
11830a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
11831a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
11832d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11833d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11834d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
11835d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    const char *pLayerName, uint32_t *pCount,
11836d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    VkExtensionProperties *pProperties) {
11837a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
11838a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
11839a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    return core_validation::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
11840d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11841d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11842d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
1184389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetDeviceProcAddr(dev, funcName);
11844d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11845d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11846d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
1184789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetInstanceProcAddr(instance, funcName);
1184808939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
11849b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11850bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
11851bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                           const char *funcName) {
11852b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return core_validation::GetPhysicalDeviceProcAddr(instance, funcName);
11853b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11854b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11855b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
11856b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct != NULL);
11857b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
11858b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11859b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    // Fill in the function pointers if our version is at least capable of having the structure contain them.
11860b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
11861b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
11862b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
11863b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
11864b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
11865b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11866b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
11867b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        core_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
11868b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
11869b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
11870b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
11871b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11872b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return VK_SUCCESS;
11873b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11874