core_validation.cpp revision 43ec3f090ca979777b306abe7c25662b9429e06d
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 <algorithm>
4094c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <assert.h>
4194c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <iostream>
4294c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <list>
4394c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <map>
44c8bee427d7a8ed0ccec899fbf47134d582dcafbdGabríel Arthúr Pétursson#include <memory>
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>
525770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus#include <inttypes.h>
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"
65d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include "shader_validation.h"
665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_table.h"
675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_data.h"
685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_extension_utils.h"
695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_utils.h"
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
825770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus// TODO: remove on NDK update (r15 will probably have proper STL impl)
835770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus#ifdef __ANDROID__
845770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausnamespace std {
855770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
865770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraustemplate <typename T>
875770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstd::string to_string(T var) {
885770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::ostringstream ss;
895770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    ss << var;
905770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return ss.str();
915770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus}
925770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus}
935770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus#endif
945770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
95d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan// This intentionally includes a cpp file
96d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan#include "vk_safe_struct.cpp"
97d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan
98d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wunamespace core_validation {
99d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
1005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_map;
1015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_set;
1020c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::unique_ptr;
1030c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::vector;
1040c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::string;
1050c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::stringstream;
1060c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::max;
1075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// WSI Image Objects bypass usual Image Object creation methods.  A special Memory
1095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Object value will be used to identify them internally.
1105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkDeviceMemory MEMTRACKER_SWAP_CHAIN_IMAGE_KEY = (VkDeviceMemory)(-1);
111888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// 2nd special memory handle used to flag object as unbound from memory
112888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisstatic const VkDeviceMemory MEMORY_UNBOUND = VkDeviceMemory(~((uint64_t)(0)) - 1);
113b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
1142e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// A special value of (0xFFFFFFFF, 0xFFFFFFFF) indicates that the surface size will be determined
1152e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// by the extent of a swapchain targeting the surface.
1162e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madillstatic const uint32_t kSurfaceSizeFromSwapchain = 0xFFFFFFFFu;
1172e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill
118f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct instance_layer_data {
119d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkInstance instance = VK_NULL_HANDLE;
120d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    debug_report_data *report_data = nullptr;
1215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<VkDebugReportCallbackEXT> logging_callback;
1229172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkLayerInstanceDispatchTable dispatch_table;
1239172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes
124219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CALL_STATE vkEnumeratePhysicalDevicesState = UNCALLED;
125219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    uint32_t physical_devices_count = 0;
126b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    CALL_STATE vkEnumeratePhysicalDeviceGroupsState = UNCALLED;
127b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    uint32_t physical_device_groups_count = 0;
128219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CHECK_DISABLED disabled = {};
129219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
130f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    unordered_map<VkPhysicalDevice, PHYSICAL_DEVICE_STATE> physical_device_map;
131747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    unordered_map<VkSurfaceKHR, SURFACE_STATE> surface_map;
132747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
1330cf009a4e2a5c22e4645f343c7a998f188a22015Chris Forbes    InstanceExtensions extensions;
134f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes};
135f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes
136f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct layer_data {
137f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    debug_report_data *report_data = nullptr;
1384a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkLayerDispatchTable dispatch_table;
13994c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis
140a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski    DeviceExtensions extensions = {};
141cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    unordered_set<VkQueue> queues;  // All queues under given device
1425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Layer specific data
143d31a44af6da568692a73201825459689c9431867Tobin Ehlis    unordered_map<VkSampler, unique_ptr<SAMPLER_STATE>> samplerMap;
14479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis    unordered_map<VkImageView, unique_ptr<IMAGE_VIEW_STATE>> imageViewMap;
1451facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    unordered_map<VkImage, unique_ptr<IMAGE_STATE>> imageMap;
14639267c0c27b8f032f05a6747eb02d4508247fdc1Tobin Ehlis    unordered_map<VkBufferView, unique_ptr<BUFFER_VIEW_STATE>> bufferViewMap;
1475cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    unordered_map<VkBuffer, unique_ptr<BUFFER_STATE>> bufferMap;
1484c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    unordered_map<VkPipeline, PIPELINE_STATE *> pipelineMap;
1498d6a38de0389036581ada119e548180c614fe0efChris Forbes    unordered_map<VkCommandPool, COMMAND_POOL_NODE> commandPoolMap;
150a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE *> descriptorPoolMap;
151397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis    unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> setMap;
152c8bee427d7a8ed0ccec899fbf47134d582dcafbdGabríel Arthúr Pétursson    unordered_map<VkDescriptorSetLayout, std::unique_ptr<cvdescriptorset::DescriptorSetLayout>> descriptorSetLayoutMap;
1535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
15457fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    unordered_map<VkDeviceMemory, unique_ptr<DEVICE_MEM_INFO>> memObjMap;
1555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkFence, FENCE_NODE> fenceMap;
15636c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    unordered_map<VkQueue, QUEUE_STATE> queueMap;
1574710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    unordered_map<VkEvent, EVENT_STATE> eventMap;
1585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<QueryObject, bool> queryToStateMap;
1595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
1605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
16172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis    unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap;
162c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    unordered_map<VkFramebuffer, unique_ptr<FRAMEBUFFER_STATE>> frameBufferMap;
1635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap;
1645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
165127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    unordered_map<VkRenderPass, unique_ptr<RENDER_PASS_STATE>> renderPassMap;
166918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes    unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap;
1676246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    unordered_map<VkDescriptorUpdateTemplateKHR, unique_ptr<TEMPLATE_STATE>> desc_template_map;
16816a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes    unordered_map<VkSwapchainKHR, std::unique_ptr<SWAPCHAIN_NODE>> swapchainMap;
16907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
170d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkDevice device = VK_NULL_HANDLE;
171ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    VkPhysicalDevice physical_device = VK_NULL_HANDLE;
1725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
173cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    instance_layer_data *instance_data = nullptr;  // from device to enclosing instance
17407a464bd7fec9583f346b8c4b8d43c88d2e9ffa4Chris Forbes
175f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes    VkPhysicalDeviceFeatures enabled_features = {};
1765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Device specific data
177d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    PHYS_DEV_PROPERTIES_NODE phys_dev_properties = {};
178d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkPhysicalDeviceMemoryProperties phys_dev_mem_props = {};
179e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    VkPhysicalDeviceProperties phys_dev_props = {};
1805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
1815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
182b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis// TODO : Do we need to guard access to layer_data_map w/ lock?
183b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlisstatic unordered_map<void *, layer_data *> layer_data_map;
184f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic unordered_map<void *, instance_layer_data *> instance_layer_data_map;
185b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
186b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Youngstatic uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
187b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
188e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wustatic const VkLayerProperties global_layer = {
189f1ea418f193d10a8455cdf47e0eeeeb1f4d8b5bfJon Ashburn    "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
190e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu};
1915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
192cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class TCreateInfo>
193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskivoid ValidateLayerOrdering(const TCreateInfo &createInfo) {
1945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool foundLayer = false;
1955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) {
196e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu        if (!strcmp(createInfo.ppEnabledLayerNames[i], global_layer.layerName)) {
1975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            foundLayer = true;
1985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
1995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This has to be logged to console as we don't have a callback at this point.
2005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) {
201bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.", global_layer.layerName);
2025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO : This can be much smarter, using separate locks for separate global data
207b9e992386a44404152747d66817a733aa127e281Jeremy Hayesstatic std::mutex global_lock;
208593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
20979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis// Return IMAGE_VIEW_STATE ptr for specified imageView or else NULL
2109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_VIEW_STATE *GetImageViewState(const layer_data *dev_data, VkImageView image_view) {
2112c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto iv_it = dev_data->imageViewMap.find(image_view);
2122c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (iv_it == dev_data->imageViewMap.end()) {
2132c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis        return nullptr;
2142c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    }
2152c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    return iv_it->second.get();
2162c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis}
2179a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis// Return sampler node ptr for specified sampler or else NULL
2189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSAMPLER_STATE *GetSamplerState(const layer_data *dev_data, VkSampler sampler) {
2192c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto sampler_it = dev_data->samplerMap.find(sampler);
2202c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (sampler_it == dev_data->samplerMap.end()) {
2219a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis        return nullptr;
2229a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    }
2239a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    return sampler_it->second.get();
2249a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis}
2255cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return image state ptr for specified image or else NULL
2269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_STATE *GetImageState(const layer_data *dev_data, VkImage image) {
2276d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    auto img_it = dev_data->imageMap.find(image);
2286d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    if (img_it == dev_data->imageMap.end()) {
2296d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        return nullptr;
2306d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    }
2316d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    return img_it->second.get();
2326d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis}
2335cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return buffer state ptr for specified buffer or else NULL
2349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_STATE *GetBufferState(const layer_data *dev_data, VkBuffer buffer) {
2352c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto buff_it = dev_data->bufferMap.find(buffer);
2362c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (buff_it == dev_data->bufferMap.end()) {
2378718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        return nullptr;
2388718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    }
2398718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    return buff_it->second.get();
2408718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis}
241b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis// Return swapchain node for specified swapchain or else NULL
2429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSWAPCHAIN_NODE *GetSwapchainNode(const layer_data *dev_data, VkSwapchainKHR swapchain) {
24316a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes    auto swp_it = dev_data->swapchainMap.find(swapchain);
24416a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes    if (swp_it == dev_data->swapchainMap.end()) {
245b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        return nullptr;
246b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    }
2473f687bf405355f3eec6bd1bc0e8d04daba37a0f9Tobin Ehlis    return swp_it->second.get();
248b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis}
2492f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis// Return buffer node ptr for specified buffer or else NULL
2509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_VIEW_STATE *GetBufferViewState(const layer_data *dev_data, VkBufferView buffer_view) {
25151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto bv_it = dev_data->bufferViewMap.find(buffer_view);
25251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (bv_it == dev_data->bufferViewMap.end()) {
2532f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis        return nullptr;
2542f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    }
2552f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    return bv_it->second.get();
2562f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis}
2578718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis
2589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFENCE_NODE *GetFenceNode(layer_data *dev_data, VkFence fence) {
25966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->fenceMap.find(fence);
26066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->fenceMap.end()) {
26166fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
26266fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
26366fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
26466fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
26566fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
2669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisEVENT_STATE *GetEventNode(layer_data *dev_data, VkEvent event) {
2679556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    auto it = dev_data->eventMap.find(event);
2689556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    if (it == dev_data->eventMap.end()) {
2699556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis        return nullptr;
2709556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    }
2719556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    return &it->second;
2729556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis}
2739556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis
2749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUERY_POOL_NODE *GetQueryPoolNode(layer_data *dev_data, VkQueryPool query_pool) {
275ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    auto it = dev_data->queryPoolMap.find(query_pool);
276ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    if (it == dev_data->queryPoolMap.end()) {
277ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis        return nullptr;
278ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    }
279ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    return &it->second;
280ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis}
281ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis
2829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUEUE_STATE *GetQueueState(layer_data *dev_data, VkQueue queue) {
28366fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->queueMap.find(queue);
28466fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->queueMap.end()) {
28566fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
28666fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
28766fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
28866fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
28966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
2909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSEMAPHORE_NODE *GetSemaphoreNode(layer_data *dev_data, VkSemaphore semaphore) {
2915e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    auto it = dev_data->semaphoreMap.find(semaphore);
2925e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    if (it == dev_data->semaphoreMap.end()) {
2935e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes        return nullptr;
2945e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    }
2955e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    return &it->second;
2965e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes}
2975e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes
2989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisCOMMAND_POOL_NODE *GetCommandPoolNode(layer_data *dev_data, VkCommandPool pool) {
2998d6a38de0389036581ada119e548180c614fe0efChris Forbes    auto it = dev_data->commandPoolMap.find(pool);
3008d6a38de0389036581ada119e548180c614fe0efChris Forbes    if (it == dev_data->commandPoolMap.end()) {
3018d6a38de0389036581ada119e548180c614fe0efChris Forbes        return nullptr;
3028d6a38de0389036581ada119e548180c614fe0efChris Forbes    }
3038d6a38de0389036581ada119e548180c614fe0efChris Forbes    return &it->second;
3048d6a38de0389036581ada119e548180c614fe0efChris Forbes}
3053bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
3069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisPHYSICAL_DEVICE_STATE *GetPhysicalDeviceState(instance_layer_data *instance_data, VkPhysicalDevice phys) {
307f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    auto it = instance_data->physical_device_map.find(phys);
308f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    if (it == instance_data->physical_device_map.end()) {
3093bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes        return nullptr;
3103bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    }
3113bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    return &it->second;
3123bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes}
3133bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
3149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSURFACE_STATE *GetSurfaceState(instance_layer_data *instance_data, VkSurfaceKHR surface) {
315747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    auto it = instance_data->surface_map.find(surface);
316747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (it == instance_data->surface_map.end()) {
317747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        return nullptr;
318747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
319747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return &it->second;
320747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
321747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
322d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris ForbesDeviceExtensions const *GetEnabledExtensions(layer_data const *dev_data) {
323d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return &dev_data->extensions;
324d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
325d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
326f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Return ptr to memory binding for given handle of specified type
3277a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic BINDABLE *GetObjectMemBinding(layer_data *dev_data, uint64_t handle, VulkanObjectType type) {
3285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type) {
3297a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        case kVulkanObjectTypeImage:
3309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetImageState(dev_data, VkImage(handle));
3317a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        case kVulkanObjectTypeBuffer:
3329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetBufferState(dev_data, VkBuffer(handle));
333cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
334cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33694c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis    return nullptr;
3375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis// prototype
3399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *, const VkCommandBuffer);
34072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis
3415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return ptr to info in map container containing mem, or NULL if not found
3425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Calls to this function should be wrapped in mutex
3439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDEVICE_MEM_INFO *GetMemObjInfo(const layer_data *dev_data, const VkDeviceMemory mem) {
34457fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    auto mem_it = dev_data->memObjMap.find(mem);
34557fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_it == dev_data->memObjMap.end()) {
3465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
3475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34857fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    return mem_it->second.get();
3495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
3505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void add_mem_obj_info(layer_data *dev_data, void *object, const VkDeviceMemory mem,
3525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             const VkMemoryAllocateInfo *pAllocateInfo) {
3535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(object != NULL);
3545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->memObjMap[mem] = unique_ptr<DEVICE_MEM_INFO>(new DEVICE_MEM_INFO(object, mem, pAllocateInfo));
3565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
357dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis
358cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given bound_object_handle, bound to given mem allocation, verify that the range for the bound object is valid
3597a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ValidateMemoryIsValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t bound_object_handle, VulkanObjectType type,
3607a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                  const char *functionName) {
3619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
362f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
363f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        if (!mem_info->bound_ranges[bound_object_handle].valid) {
364f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
3659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
366dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           "%s: Cannot read invalid region of memory allocation 0x%" PRIx64 " for bound %s object 0x%" PRIx64
367dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           ", please fill the memory before using.",
3689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           functionName, HandleToUint64(mem), object_string[type], bound_object_handle);
369f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        }
370f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
371f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    return false;
372f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
3731facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis// For given image_state
3741facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then verify that image_state valid member is true
375f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else verify that the image's bound memory range is valid
37660568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageMemoryIsValid(layer_data *dev_data, IMAGE_STATE *image_state, const char *functionName) {
377e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
3781facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        if (!image_state->valid) {
379f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
3809b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(image_state->binding.mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
381414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                           "%s: Cannot read invalid swapchain image 0x%" PRIx64 ", please fill the memory before using.",
3829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           functionName, HandleToUint64(image_state->image));
3835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
3845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
3859b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        return ValidateMemoryIsValid(dev_data, image_state->binding.mem, HandleToUint64(image_state->image), kVulkanObjectTypeImage,
3869b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                     functionName);
3875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
3895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
3905cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// For given buffer_state, verify that the range it's bound to is valid
391c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskibool ValidateBufferMemoryIsValid(layer_data *dev_data, BUFFER_STATE *buffer_state, const char *functionName) {
3929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    return ValidateMemoryIsValid(dev_data, buffer_state->binding.mem, HandleToUint64(buffer_state->buffer), kVulkanObjectTypeBuffer,
3939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                 functionName);
394f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
395f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For the given memory allocation, set the range bound by the given handle object to the valid param value
396f989de4217bce0f293121d0da53dc8328276370fTobin Ehlisstatic void SetMemoryValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, bool valid) {
3979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
398f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
399f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        mem_info->bound_ranges[handle].valid = valid;
400f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
401f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
402f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given image node
4031facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then set entire image_state to valid param value
404f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else set the image's bound memory range to valid param value
405623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinskivoid SetImageMemoryValid(layer_data *dev_data, IMAGE_STATE *image_state, bool valid) {
406e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
4071facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->valid = valid;
4085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
4099b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        SetMemoryValid(dev_data, image_state->binding.mem, HandleToUint64(image_state->image), valid);
4105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
412f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given buffer node set the buffer's bound memory range to valid param value
413c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskivoid SetBufferMemoryValid(layer_data *dev_data, BUFFER_STATE *buffer_state, bool valid) {
4149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    SetMemoryValid(dev_data, buffer_state->binding.mem, HandleToUint64(buffer_state->buffer), valid);
415f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
416ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
41756f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given sampler and command buffer node
418d31a44af6da568692a73201825459689c9431867Tobin Ehlisvoid AddCommandBufferBindingSampler(GLOBAL_CB_NODE *cb_node, SAMPLER_STATE *sampler_state) {
419d31a44af6da568692a73201825459689c9431867Tobin Ehlis    sampler_state->cb_bindings.insert(cb_node);
4209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(sampler_state->sampler), kVulkanObjectTypeSampler});
42156f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis}
42256f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis
42356f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given image node and command buffer node
4241facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisvoid AddCommandBufferBindingImage(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state) {
425ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Skip validation if this image was created through WSI
426e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
427ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // First update CB binding in MemObj mini CB list
428d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        for (auto mem_binding : image_state->GetBoundMemory()) {
4299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
430d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            if (pMemInfo) {
431d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                pMemInfo->cb_bindings.insert(cb_node);
432d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                // Now update CBInfo's Mem reference list
433d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                cb_node->memObjs.insert(mem_binding);
434d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            }
435ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        }
436f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        // Now update cb binding for image
4379b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        cb_node->object_bindings.insert({HandleToUint64(image_state->image), kVulkanObjectTypeImage});
4381facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->cb_bindings.insert(cb_node);
439ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
440ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
441ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
44203ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis// Create binding link between given image view node and its image with command buffer node
44303ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlisvoid AddCommandBufferBindingImageView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state) {
44403ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // First add bindings for imageView
44503ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
4469b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(view_state->image_view), kVulkanObjectTypeImageView});
4479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, view_state->create_info.image);
44803ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // Add bindings for image within imageView
4491facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
4501facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
45103ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    }
45203ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis}
45303ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis
454ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis// Create binding link between given buffer node and command buffer node
4555cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlisvoid AddCommandBufferBindingBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state) {
456ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // First update CB binding in MemObj mini CB list
4575cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    for (auto mem_binding : buffer_state->GetBoundMemory()) {
4589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
459d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        if (pMemInfo) {
460d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            pMemInfo->cb_bindings.insert(cb_node);
461d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            // Now update CBInfo's Mem reference list
462d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            cb_node->memObjs.insert(mem_binding);
463d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        }
464ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
465ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Now update cb binding for buffer
4669b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(buffer_state->buffer), kVulkanObjectTypeBuffer});
4675cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    buffer_state->cb_bindings.insert(cb_node);
468ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
469ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
47077b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis// Create binding link between given buffer view node and its buffer with command buffer node
47177b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlisvoid AddCommandBufferBindingBufferView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_VIEW_STATE *view_state) {
47277b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // First add bindings for bufferView
47377b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
4749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(view_state->buffer_view), kVulkanObjectTypeBufferView});
4759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, view_state->create_info.buffer);
47677b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // Add bindings for buffer within bufferView
4775cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
4785cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, buffer_state);
47977b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    }
48077b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis}
48177b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis
482400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis// For every mem obj bound to particular CB, free bindings related to that CB
483d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlisstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
484d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis    if (cb_node) {
485d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        if (cb_node->memObjs.size() > 0) {
486d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            for (auto mem : cb_node->memObjs) {
4879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                DEVICE_MEM_INFO *pInfo = GetMemObjInfo(dev_data, mem);
4885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pInfo) {
489d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                    pInfo->cb_bindings.erase(cb_node);
4905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
4915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
492d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            cb_node->memObjs.clear();
4935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
494d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        cb_node->validate_functions.clear();
4955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
498f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Clear a single object binding from given memory object, or report error if binding is missing
4997a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ClearMemoryObjectBinding(layer_data *dev_data, uint64_t handle, VulkanObjectType type, VkDeviceMemory mem) {
5009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
501f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // This obj is bound to a memory object. Remove the reference to this object in that memory object's list
502d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes    if (mem_info) {
503d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes        mem_info->obj_bindings.erase({handle, type});
504f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    }
505f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return false;
506f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis}
507f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis
508f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// ClearMemoryObjectBindings clears the binding of objects to memory
509f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  For the given object it pulls the memory bindings and makes sure that the bindings
510f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  no longer refer to the object being cleared. This occurs when objects are destroyed.
5117a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskibool ClearMemoryObjectBindings(layer_data *dev_data, uint64_t handle, VulkanObjectType type) {
512f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    bool skip = false;
513f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
514f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (mem_binding) {
515f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (!mem_binding->sparse) {
516f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            skip = ClearMemoryObjectBinding(dev_data, handle, type, mem_binding->binding.mem);
517cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Sparse, clear all bindings
518bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            for (auto &sparse_mem_binding : mem_binding->sparse_bindings) {
519f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                skip |= ClearMemoryObjectBinding(dev_data, handle, type, sparse_mem_binding.mem);
5205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
5215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
523f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return skip;
5245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
526888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// For given mem object, verify that it is not null or UNBOUND, if it is, report error. Return skip value.
527888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisbool VerifyBoundMemoryIsValid(const layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, const char *api_name,
52835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                              const char *type_name, UNIQUE_VALIDATION_ERROR_CODE error_code) {
529888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    bool result = false;
530888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    if (VK_NULL_HANDLE == mem) {
531888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
532cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
533cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound. Memory should be bound by calling "
534cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "vkBind%sMemory(). %s",
53535ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, type_name, validation_error_map[error_code]);
536888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    } else if (MEMORY_UNBOUND == mem) {
537888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
538cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
539cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound and previously bound memory was freed. "
540cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "Memory must not be freed prior to this operation. %s",
54135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, validation_error_map[error_code]);
542888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    }
543888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    return result;
544888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis}
545888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis
546b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was ever bound to this image
54735ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToImage(const layer_data *dev_data, const IMAGE_STATE *image_state, const char *api_name,
54835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                  UNIQUE_VALIDATION_ERROR_CODE error_code) {
549b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
5501facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (0 == (static_cast<uint32_t>(image_state->createInfo.flags) & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
5519b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        result = VerifyBoundMemoryIsValid(dev_data, image_state->binding.mem, HandleToUint64(image_state->image), api_name, "Image",
5529b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                          error_code);
553b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
554b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
555b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
556b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
557b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was bound to this buffer
55835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToBuffer(const layer_data *dev_data, const BUFFER_STATE *buffer_state, const char *api_name,
55935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                   UNIQUE_VALIDATION_ERROR_CODE error_code) {
560b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
5615cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (0 == (static_cast<uint32_t>(buffer_state->createInfo.flags) & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) {
5629b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        result = VerifyBoundMemoryIsValid(dev_data, buffer_state->binding.mem, HandleToUint64(buffer_state->buffer), api_name,
5639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                          "Buffer", error_code);
564b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
565b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
566b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
567b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
5683a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// SetMemBinding is used to establish immutable, non-sparse binding between a single image/buffer object and memory object.
5693a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Corresponding valid usage checks are in ValidateSetMemBinding().
5707a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic void SetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VulkanObjectType type, const char *apiName) {
571c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    if (mem != VK_NULL_HANDLE) {
572c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
573c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        assert(mem_binding);
574c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
575c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        if (mem_info) {
576c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_info->obj_bindings.insert({handle, type});
577c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // For image objects, make sure default memory state is correctly set
578c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // TODO : What's the best/correct way to handle this?
5797a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            if (kVulkanObjectTypeImage == type) {
580c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                auto const image_state = GetImageState(dev_data, VkImage(handle));
581c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                if (image_state) {
582c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    VkImageCreateInfo ici = image_state->createInfo;
583c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
584c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                        // TODO::  More memory state transition stuff.
585c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    }
586c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                }
587c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            }
588c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_binding->binding.mem = mem;
589c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        }
590c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    }
591c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton}
5923a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton
5933a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Valid usage checks for a call to SetMemBinding().
5943a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// For NULL mem case, output warning
5953a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Make sure given object is in global object map
5963a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  IF a previous binding existed, output validation error
5973a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Otherwise, add reference from objectInfo to memoryInfo
5983a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Add reference off of objInfo
5993a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// TODO: We may need to refactor or pass in multiple valid usage statements to handle multiple valid usage conditions.
6007a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ValidateSetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VulkanObjectType type,
601c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                                  const char *apiName) {
6023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
603f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // It's an error to bind an object to NULL memory
604d3876b4ff7c293a14f73fe3622513d1fa91bf2d0Jeremy Hayes    if (mem != VK_NULL_HANDLE) {
605f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
606888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        assert(mem_binding);
60710ffe2d353eaff714ed92a2835af77d8b5042d31Cort        if (mem_binding->sparse) {
608315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_1740082a;
60910ffe2d353eaff714ed92a2835af77d8b5042d31Cort            const char *handle_type = "IMAGE";
61074300755ed9ec780d6073af71e47f201217008d6Cort Stratton            if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
611315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                error_code = VALIDATION_ERROR_1700080c;
61210ffe2d353eaff714ed92a2835af77d8b5042d31Cort                handle_type = "BUFFER";
61310ffe2d353eaff714ed92a2835af77d8b5042d31Cort            } else {
61474300755ed9ec780d6073af71e47f201217008d6Cort Stratton                assert(strcmp(apiName, "vkBindImageMemory()") == 0);
61510ffe2d353eaff714ed92a2835af77d8b5042d31Cort            }
6163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
6179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem), __LINE__, error_code, "MEM",
6183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
6193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") which was created with sparse memory flags (VK_%s_CREATE_SPARSE_*_BIT). %s",
6209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            apiName, HandleToUint64(mem), handle, handle_type, validation_error_map[error_code]);
62110ffe2d353eaff714ed92a2835af77d8b5042d31Cort        }
6229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
623888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        if (mem_info) {
6249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *prev_binding = GetMemObjInfo(dev_data, mem_binding->binding.mem);
625888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis            if (prev_binding) {
626315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_17400828;
62774300755ed9ec780d6073af71e47f201217008d6Cort Stratton                if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
628315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    error_code = VALIDATION_ERROR_1700080a;
62998c2a17e1a549df84f4239f619bc0955f632cb43Cort                } else {
63074300755ed9ec780d6073af71e47f201217008d6Cort Stratton                    assert(strcmp(apiName, "vkBindImageMemory()") == 0);
63198c2a17e1a549df84f4239f619bc0955f632cb43Cort                }
6323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
6339b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(mem), __LINE__, error_code, "MEM",
6343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
6353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                ") which has already been bound to mem object 0x%" PRIxLEAST64 ". %s",
6369b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                apiName, HandleToUint64(mem), handle, HandleToUint64(prev_binding->mem),
6373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                validation_error_map[error_code]);
638f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            } else if (mem_binding->binding.mem == MEMORY_UNBOUND) {
6393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
6409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(mem), __LINE__, MEMTRACK_REBIND_OBJECT, "MEM",
6413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
6423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                ") which was previous bound to memory that has since been freed. Memory bindings are immutable in "
6433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "Vulkan so this attempt to bind to new memory is not allowed.",
6449b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                apiName, HandleToUint64(mem), handle);
6455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
6465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
6495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For NULL mem case, clear any previous binding Else...
6525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Make sure given object is in its object map
6535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  IF a previous binding existed, update binding
6545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference from objectInfo to memoryInfo
6555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference off of object's binding info
6560a1ce3dfd81c9f4efbe46f5ba5ddaea70bc4aa61Chris Forbes// Return VK_TRUE if addition is successful, VK_FALSE otherwise
657ece0e981ee4a5ad2572d146a89fc64d699d79f36Chris Forbesstatic bool SetSparseMemBinding(layer_data *dev_data, MEM_BINDING binding, uint64_t handle, VulkanObjectType type) {
6583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = VK_FALSE;
6595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Handle NULL case separately, just clear previous binding & decrement reference
660f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (binding.mem == VK_NULL_HANDLE) {
661f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        // TODO : This should cause the range of the resource to be unbound according to spec
6625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
663f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
664f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding);
665f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding->sparse);
6669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, binding.mem);
667f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (mem_info) {
668f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_info->obj_bindings.insert({handle, type});
6692e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis            // Need to set mem binding for this object
670f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_binding->sparse_bindings.insert(binding);
6715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
674caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis}
675caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis
6765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Check object status for selected flag state
67751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool validate_status(layer_data *dev_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
6784f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            const char *fail_msg, UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
6793d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (!(pNode->status & status_mask)) {
6804f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        char const *const message = validation_error_map[msg_code];
68151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(pNode->commandBuffer), __LINE__, msg_code, "DS", "command buffer object 0x%p: %s. %s.",
6839b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       pNode->commandBuffer, fail_msg, message);
6845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
685e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
6865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Retrieve pipeline node ptr for given pipeline object
68951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_STATE *getPipelineState(layer_data const *dev_data, VkPipeline pipeline) {
69051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineMap.find(pipeline);
69151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineMap.end()) {
692ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        return nullptr;
6935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
694ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    return it->second;
6955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisRENDER_PASS_STATE *GetRenderPassState(layer_data const *dev_data, VkRenderPass renderpass) {
69851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->renderPassMap.find(renderpass);
69951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->renderPassMap.end()) {
70016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes        return nullptr;
70116387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes    }
702fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    return it->second.get();
70316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes}
70416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes
7059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFRAMEBUFFER_STATE *GetFramebufferState(const layer_data *dev_data, VkFramebuffer framebuffer) {
70651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->frameBufferMap.find(framebuffer);
70751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->frameBufferMap.end()) {
708f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes        return nullptr;
709f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes    }
71004861caca7eb93a5241b164e8480bb93c826902cTobin Ehlis    return it->second.get();
711f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes}
712f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes
7139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSetLayout const *GetDescriptorSetLayout(layer_data const *dev_data, VkDescriptorSetLayout dsLayout) {
71451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->descriptorSetLayoutMap.find(dsLayout);
71551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->descriptorSetLayoutMap.end()) {
71611f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes        return nullptr;
71711f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    }
718c8bee427d7a8ed0ccec899fbf47134d582dcafbdGabríel Arthúr Pétursson    return it->second.get();
71911f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes}
72011f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes
72151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_LAYOUT_NODE const *getPipelineLayout(layer_data const *dev_data, VkPipelineLayout pipeLayout) {
72251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineLayoutMap.find(pipeLayout);
72351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineLayoutMap.end()) {
7244a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes        return nullptr;
7254a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    }
7264a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    return &it->second;
7274a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes}
7284a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes
729d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesshader_module const *GetShaderModuleState(layer_data const *dev_data, VkShaderModule module) {
730d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto it = dev_data->shaderModuleMap.find(module);
731d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (it == dev_data->shaderModuleMap.end()) {
732d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return nullptr;
733d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
734d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return it->second.get();
735d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
736d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
737e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if for a given PSO, the given state enum is dynamic, else return false
7384c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool isDynamic(const PIPELINE_STATE *pPipeline, const VkDynamicState state) {
7395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) {
7405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
741cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) return true;
7425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
744e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
7455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
7465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate state stored as flags at time of draw call
7484f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayesstatic bool validate_draw_state_flags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe, bool indexed,
7494f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                      UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
7509c4006684a13db43f0dbc8d0015a9ef34872ca09Chris Forbes    bool result = false;
751ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipe->graphicsPipelineCI.pInputAssemblyState &&
752ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        ((pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
753ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         (pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP))) {
7543d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_LINE_WIDTH_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7554f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic line width state not set for this command buffer", msg_code);
7563d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
75745824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pRasterizationState &&
75845824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pRasterizationState->depthBiasEnable == VK_TRUE)) {
7593d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BIAS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7604f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bias state not set for this command buffer", msg_code);
7613d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
7623d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->blendConstantsEnabled) {
7633d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_BLEND_CONSTANTS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7644f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic blend constants state not set for this command buffer", msg_code);
7653d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
76645824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
76745824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE)) {
7683d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BOUNDS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7694f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bounds state not set for this command buffer", msg_code);
7703d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
77145824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
77245824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->stencilTestEnable == VK_TRUE)) {
7733d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7744f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil read mask state not set for this command buffer", msg_code);
7753d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7764f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil write mask state not set for this command buffer", msg_code);
7773d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7784f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil reference state not set for this command buffer", msg_code);
7793d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
7801c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (indexed) {
7813d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_INDEX_BUFFER_BOUND, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7824f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Index buffer object not bound to this command buffer when Indexed Draw attempted", msg_code);
7833d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
7844f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes
7855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
7865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
7875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify attachment reference compatibility according to spec
7895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this
7905ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski//  If both AttachmentReference arrays have requested index, check their corresponding AttachmentDescriptions
7915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//   to make sure that format and samples counts match.
7925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If not, they are not compatible.
7935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary,
7945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments,
7955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentReference *pSecondary, const uint32_t secondaryCount,
7965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentDescription *pSecondaryAttachments) {
797e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    // Check potential NULL cases first to avoid nullptr issues later
798e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    if (pPrimary == nullptr) {
799e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        if (pSecondary == nullptr) {
800e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis            return true;
801e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        }
802e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
803e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    } else if (pSecondary == nullptr) {
804e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
805e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    }
806cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (index >= primaryCount) {  // Check secondary as if primary is VK_ATTACHMENT_UNUSED
807cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pSecondary[index].attachment) return true;
808cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (index >= secondaryCount) {  // Check primary as if secondary is VK_ATTACHMENT_UNUSED
809cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pPrimary[index].attachment) return true;
810cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // Format and sample count must match
8115ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) && (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
8125ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return true;
8135ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        } else if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) || (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
8145ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return false;
8155ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        }
8165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((pPrimaryAttachments[pPrimary[index].attachment].format ==
8175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].format) &&
8185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (pPrimaryAttachments[pPrimary[index].attachment].samples ==
8195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].samples))
8205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return true;
8215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Format and sample counts didn't match
8235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
8245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
825a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// TODO : Scrub verify_renderpass_compatibility() and validateRenderPassCompatibility() and unify them and/or share code
826266231a5421564c314f6b5d5bd3fed26fd389484Chris Forbes// For given primary RenderPass object and secondary RenderPassCreateInfo, verify that they're compatible
82751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verify_renderpass_compatibility(const layer_data *dev_data, const VkRenderPassCreateInfo *primaryRPCI,
8288da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                            const VkRenderPassCreateInfo *secondaryRPCI, string &errorMsg) {
8295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
830c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
8315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
8325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses.";
8335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
8345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
8355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t spIndex = 0;
8375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) {
8385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible
8395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
8405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
8415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount);
8425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) {
8435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount,
8445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments,
8455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
846c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
8475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
8485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
8495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
8505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments,
8515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         primaryColorCount, primaryRPCI->pAttachments,
8525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryRPCI->pSubpasses[spIndex].pResolveAttachments,
8535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryColorCount, secondaryRPCI->pAttachments)) {
854c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
8555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
8565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
8575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
8585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
860fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
861bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (!attachment_references_compatible(0, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 1,
862bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
863fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes                                              1, secondaryRPCI->pAttachments)) {
864c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes            stringstream errorStr;
865fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorStr << "depth/stencil attachments of subpass index " << spIndex << " are not compatible.";
866fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorMsg = errorStr.str();
867fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            return false;
868fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes        }
869fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
8705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
8715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
8725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount);
8735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < inputMax; ++i) {
8741e49a9dd0518c3cd335dd040218aa9c25d7cb600Tobin Ehlis            if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryInputCount,
8755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments,
8761e49a9dd0518c3cd335dd040218aa9c25d7cb600Tobin Ehlis                                                  secondaryInputCount, secondaryRPCI->pAttachments)) {
877c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
8785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible.";
8795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
8805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
8815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return true;
8855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Set node ptr for specified set or else NULL
8889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSet *GetSetNode(const layer_data *dev_data, VkDescriptorSet set) {
88951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto set_it = dev_data->setMap.find(set);
89051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (set_it == dev_data->setMap.end()) {
8915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
8925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
893104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return set_it->second;
8945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
896eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// For given pipeline, return number of MSAA samples, or one if MSAA disabled
8974c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic VkSampleCountFlagBits getNumSamples(PIPELINE_STATE const *pipe) {
898ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    if (pipe->graphicsPipelineCI.pMultisampleState != NULL &&
899ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pipe->graphicsPipelineCI.pMultisampleState->sType) {
900eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        return pipe->graphicsPipelineCI.pMultisampleState->rasterizationSamples;
901eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
902eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return VK_SAMPLE_COUNT_1_BIT;
903eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
904eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
905bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void list_bits(std::ostream &s, uint32_t bits) {
906b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    for (int i = 0; i < 32 && bits; i++) {
907b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        if (bits & (1 << i)) {
908b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            s << i;
909b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            bits &= ~(1 << i);
910b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (bits) {
911b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                s << ",";
912b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            }
913b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        }
914b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    }
915b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes}
916b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
917eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// Validate draw-time state related to the PSO
91851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidatePipelineDrawtimeState(layer_data const *dev_data, LAST_BOUND_STATE const &state, const GLOBAL_CB_NODE *pCB,
9194c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                          PIPELINE_STATE const *pPipeline) {
9203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
92129d196e071b2dc1db47702085469396f2b956820Chris Forbes
922d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen    // Verify vertex binding
92329d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (pPipeline->vertexBindingDescriptions.size() > 0) {
92429d196e071b2dc1db47702085469396f2b956820Chris Forbes        for (size_t i = 0; i < pPipeline->vertexBindingDescriptions.size(); i++) {
925312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            auto vertex_binding = pPipeline->vertexBindingDescriptions[i].binding;
926312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            if ((pCB->currentDrawData.buffers.size() < (vertex_binding + 1)) ||
927312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis                (pCB->currentDrawData.buffers[vertex_binding] == VK_NULL_HANDLE)) {
9283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
929df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "The Pipeline State Object (0x%" PRIxLEAST64
932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            ") expects that this Command Buffer's vertex binding Index %u "
933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct "
934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "at index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
9359b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(state.pipeline_state->pipeline), vertex_binding, i, vertex_binding);
93629d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
93729d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
93829d196e071b2dc1db47702085469396f2b956820Chris Forbes    } else {
93958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        if (!pCB->currentDrawData.buffers.empty() && !pCB->vertex_buffer_used) {
9403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
9419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCB->commandBuffer), __LINE__,
9429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
9433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Vertex buffers are bound to command buffer (0x%p"
9443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") but no vertex buffers are attached to this Pipeline State Object (0x%" PRIxLEAST64 ").",
9459b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pCB->commandBuffer, HandleToUint64(state.pipeline_state->pipeline));
94629d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
94729d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
94829d196e071b2dc1db47702085469396f2b956820Chris Forbes    // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
94929d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip check if rasterization is disabled or there is no viewport.
95029d196e071b2dc1db47702085469396f2b956820Chris Forbes    if ((!pPipeline->graphicsPipelineCI.pRasterizationState ||
95129d196e071b2dc1db47702085469396f2b956820Chris Forbes         (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) &&
95229d196e071b2dc1db47702085469396f2b956820Chris Forbes        pPipeline->graphicsPipelineCI.pViewportState) {
95329d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
95429d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
955b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
95629d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynViewport) {
957b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredViewportsMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->viewportCount) - 1;
958b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingViewportMask = ~pCB->viewportMask & requiredViewportsMask;
959b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingViewportMask) {
960b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
961b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic viewport(s) ";
962b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingViewportMask);
963d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetViewport().";
9643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
9653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
96629d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
96729d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
968b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
96929d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynScissor) {
970b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredScissorMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->scissorCount) - 1;
971b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingScissorMask = ~pCB->scissorMask & requiredScissorMask;
972b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingScissorMask) {
973b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
974b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic scissor(s) ";
975b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingScissorMask);
976d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetScissor().";
9773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
9783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
97929d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
98029d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
98129d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
98229d196e071b2dc1db47702085469396f2b956820Chris Forbes
98329d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Verify that any MSAA request in PSO matches sample# in bound FB
98429d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip the check if rasterization is disabled.
98529d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
98629d196e071b2dc1db47702085469396f2b956820Chris Forbes        (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
98729d196e071b2dc1db47702085469396f2b956820Chris Forbes        VkSampleCountFlagBits pso_num_samples = getNumSamples(pPipeline);
98829d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (pCB->activeRenderPass) {
989fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes            auto const render_pass_info = pCB->activeRenderPass->createInfo.ptr();
99029d196e071b2dc1db47702085469396f2b956820Chris Forbes            const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass];
99129d196e071b2dc1db47702085469396f2b956820Chris Forbes            uint32_t i;
99276957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            unsigned subpass_num_samples = 0;
9930a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
99429d196e071b2dc1db47702085469396f2b956820Chris Forbes            for (i = 0; i < subpass_desc->colorAttachmentCount; i++) {
99576957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pColorAttachments[i].attachment;
99676957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                if (attachment != VK_ATTACHMENT_UNUSED)
99776957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                    subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
99829d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
9990a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
100076957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            if (subpass_desc->pDepthStencilAttachment &&
100176957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
100276957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
100376957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
100429d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
1005eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
10060dc3fd4e57b8531638781daa01a2fb5d1048a6fbJamie Madill            if (subpass_num_samples && static_cast<unsigned>(pso_num_samples) != subpass_num_samples) {
10073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
10089b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
10099b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Num samples mismatch! At draw-time in Pipeline (0x%" PRIxLEAST64
10109b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                ") with %u samples while current RenderPass (0x%" PRIxLEAST64 ") w/ %u samples!",
10119b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), pso_num_samples,
10129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pCB->activeRenderPass->renderPass), subpass_num_samples);
1013eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young            }
101429d196e071b2dc1db47702085469396f2b956820Chris Forbes        } else {
10153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
10169b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
10173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "No active render pass found at draw-time in Pipeline (0x%" PRIxLEAST64 ")!",
10189b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline));
1019eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        }
1020eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
1021528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    // Verify that PSO creation renderPass is compatible with active renderPass
1022528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    if (pCB->activeRenderPass) {
1023528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        std::string err_string;
1024a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if ((pCB->activeRenderPass->renderPass != pPipeline->graphicsPipelineCI.renderPass) &&
102551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(), pPipeline->render_pass_ci.ptr(),
1026528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                                             err_string)) {
1027528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            // renderPass that PSO was created with must be compatible with active renderPass that PSO is being used with
10283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
10299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
10309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "At Draw time the active render pass (0x%" PRIxLEAST64
10319b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            ") is incompatible w/ gfx pipeline "
10329b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "(0x%" PRIxLEAST64 ") that was created w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
10339b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->activeRenderPass->renderPass), HandleToUint64(pPipeline->pipeline),
10349b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->graphicsPipelineCI.renderPass), err_string.c_str());
1035528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        }
1036c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes
1037c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        if (pPipeline->graphicsPipelineCI.subpass != pCB->activeSubpass) {
10383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
10399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
10409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Pipeline was built for subpass %u but used in subpass %u", pPipeline->graphicsPipelineCI.subpass,
10413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            pCB->activeSubpass);
1042c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        }
1043528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    }
104429d196e071b2dc1db47702085469396f2b956820Chris Forbes    // TODO : Add more checks here
104529d196e071b2dc1db47702085469396f2b956820Chris Forbes
10463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
1047eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
1048eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
1049d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
1050d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// pipelineLayout[layoutIndex]
1051d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool verify_set_layout_compatibility(const cvdescriptorset::DescriptorSet *descriptor_set,
1052d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                            PIPELINE_LAYOUT_NODE const *pipeline_layout, const uint32_t layoutIndex,
1053d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                            string &errorMsg) {
1054d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto num_sets = pipeline_layout->set_layouts.size();
1055d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (layoutIndex >= num_sets) {
1056d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        stringstream errorStr;
1057d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        errorStr << "VkPipelineLayout (" << pipeline_layout->layout << ") only contains " << num_sets
1058d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                 << " setLayouts corresponding to sets 0-" << num_sets - 1 << ", but you're attempting to bind set to index "
1059d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                 << layoutIndex;
1060d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        errorMsg = errorStr.str();
1061d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return false;
1062d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1063d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto layout_node = pipeline_layout->set_layouts[layoutIndex];
1064d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return descriptor_set->IsCompatible(layout_node, &errorMsg);
1065d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1066d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
10675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate overall state at the time of a draw call
106851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const bool indexed,
10694f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              const VkPipelineBindPoint bind_point, const char *function,
10704f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
1071e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
10721c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_node->lastBound[bind_point];
10734c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
107422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    if (nullptr == pPipe) {
107522fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        result |= log_msg(
1076df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
10779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            HandleToUint64(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_PIPELINE, "DS",
107822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            "At Draw/Dispatch time no valid VkPipeline is bound! This is illegal. Please bind one with vkCmdBindPipeline().");
107922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        // Early return as any further checks below will be busted w/o a pipeline
1080cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (result) return true;
108122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
10823d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // First check flag states
10831c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point)
108451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        result = validate_draw_state_flags(dev_data, cb_node, pPipe, indexed, msg_code);
10857a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis
10865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Now complete other state checks
108769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
108822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        string errorString;
108969b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        auto pipeline_layout = pPipe->pipeline_layout;
1090169c4506062f06d6676eb4da3c9e0437d1d9d659Chris Forbes
10911c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
10921c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
109322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            // If valid set is not bound throw an error
109422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
10959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                result |=
10969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
10979b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_node->commandBuffer), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS",
10989b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "VkPipeline 0x%" PRIxLEAST64 " uses set #%u but that set is not bound.",
10999b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipe->pipeline), setIndex);
110012b7fc342b53fbdd399aae4a85959e37685936acChris Forbes            } else if (!verify_set_layout_compatibility(state.boundDescriptorSets[setIndex], &pipeline_layout, setIndex,
110169b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                                        errorString)) {
110269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                // Set is bound but not compatible w/ overlapping pipeline_layout from PSO
110371511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                VkDescriptorSet setHandle = state.boundDescriptorSets[setIndex]->GetSet();
110422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                result |=
110551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
11069b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(setHandle), __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
1107414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            "VkDescriptorSet (0x%" PRIxLEAST64
1108414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") bound as set #%u is not compatible with overlapping VkPipelineLayout 0x%" PRIxLEAST64 " due to: %s",
11099b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(setHandle), setIndex, HandleToUint64(pipeline_layout.layout), errorString.c_str());
1110cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {  // Valid set is bound and layout compatible, validate that it's updated
111122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Pull the set node
11121c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
11137433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                // Validate the draw-time state for this descriptor set
11147433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                std::string err_str;
11150db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                if (!descriptor_set->ValidateDrawState(set_binding_pair.second, state.dynamicOffsets[setIndex], cb_node, function,
11160db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                                                       &err_str)) {
11171c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    auto set = descriptor_set->GetSet();
11180db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                    result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
11199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                      VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(set), __LINE__,
11209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                      DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
11210db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                                      "Descriptor set 0x%" PRIxLEAST64 " encountered the following validation error at %s time: %s",
11229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                      HandleToUint64(set), function, err_str.c_str());
11237433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                }
11245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
112522fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        }
112622fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
1127eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
1128eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    // Check general pipeline state that needs to be validated at drawtime
112951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) result |= ValidatePipelineDrawtimeState(dev_data, state, cb_node, pPipe);
1130eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
11315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
11325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
11335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
113451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const VkPipelineBindPoint bind_point) {
11351c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_state->lastBound[bind_point];
1136ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
1137ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
11381c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
11391c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
1140ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Pull the set node
11411c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
1142ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Bind this set and its active descriptor resources to the command buffer
11431c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->BindCommandBuffer(cb_state, set_binding_pair.second);
11447433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis            // For given active slots record updated images & buffers
11451c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->GetStorageUpdates(set_binding_pair.second, &cb_state->updateBuffers, &cb_state->updateImages);
1146ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis        }
1147ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    }
114858b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (pPipe->vertexBindingDescriptions.size() > 0) {
114958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        cb_state->vertex_buffer_used = true;
115058b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
1151ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis}
1152ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis
1153a27508babf63d50aea75883a3702979193c23683Mark Young// Validate HW line width capabilities prior to setting requested line width.
115406727c7f56d1080aff506a9ae1ae9d8c174b3e9dMark Lobodzinskistatic bool verifyLineWidth(layer_data *dev_data, DRAW_STATE_ERROR dsError, VulkanObjectType object_type, const uint64_t &target,
115506727c7f56d1080aff506a9ae1ae9d8c174b3e9dMark Lobodzinski                            float lineWidth) {
11563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1157a27508babf63d50aea75883a3702979193c23683Mark Young
1158a27508babf63d50aea75883a3702979193c23683Mark Young    // First check to see if the physical device supports wide lines.
115951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if ((VK_FALSE == dev_data->enabled_features.wideLines) && (1.0f != lineWidth)) {
11603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object_type], target, __LINE__,
11613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        dsError, "DS",
11623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Attempt to set lineWidth to %f but physical device wideLines feature "
11633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "not supported/enabled so lineWidth must be 1.0f!",
11643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        lineWidth);
1165a27508babf63d50aea75883a3702979193c23683Mark Young    } else {
1166a27508babf63d50aea75883a3702979193c23683Mark Young        // Otherwise, make sure the width falls in the valid range.
116751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if ((dev_data->phys_dev_properties.properties.limits.lineWidthRange[0] > lineWidth) ||
116851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            (dev_data->phys_dev_properties.properties.limits.lineWidthRange[1] < lineWidth)) {
11693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object_type], target,
11703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, dsError, "DS",
11713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Attempt to set lineWidth to %f but physical device limits line width "
11723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "to between [%f, %f]!",
11733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            lineWidth, dev_data->phys_dev_properties.properties.limits.lineWidthRange[0],
11743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            dev_data->phys_dev_properties.properties.limits.lineWidthRange[1]);
1175a27508babf63d50aea75883a3702979193c23683Mark Young        }
1176a27508babf63d50aea75883a3702979193c23683Mark Young    }
1177a27508babf63d50aea75883a3702979193c23683Mark Young
11783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
1179a27508babf63d50aea75883a3702979193c23683Mark Young}
1180a27508babf63d50aea75883a3702979193c23683Mark Young
11815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify that create state for a pipeline is valid
118251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verifyPipelineCreateState(layer_data *dev_data, std::vector<PIPELINE_STATE *> pPipelines, int pipelineIndex) {
11833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
11845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11854c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipeline = pPipelines[pipelineIndex];
11865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If create derivative bit is set, check that we've specified a base
11885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // pipeline correctly, and that the base pipeline was created to allow
11895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // derivatives.
11905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
11914c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pBasePipeline = nullptr;
11925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^
11935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis              (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) {
1194315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // This check is a superset of VALIDATION_ERROR_096005a8 and VALIDATION_ERROR_096005aa
11953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
11969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
11979b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified");
11985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) {
11995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) {
12003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
1201df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1202315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_208005a0, "DS",
1203f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline. %s",
1204315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_208005a0]);
12055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
12065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex];
12075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
120951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            pBasePipeline = getPipelineState(dev_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
12105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
12133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
12149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
12159b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives.");
12165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
1220fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const safe_VkPipelineColorBlendStateCreateInfo *color_blend_state = pPipeline->graphicsPipelineCI.pColorBlendState;
12219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto const render_pass_info = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass)->createInfo.ptr();
1222fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pPipeline->graphicsPipelineCI.subpass];
1223fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        if (color_blend_state->attachmentCount != subpass_desc->colorAttachmentCount) {
12243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(
122551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1226315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005d4, "DS",
1227fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                "vkCreateGraphicsPipelines(): Render pass (0x%" PRIxLEAST64
1228fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                ") subpass %u has colorAttachmentCount of %u which doesn't match the pColorBlendState->attachmentCount of %u. %s",
12299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(pPipeline->graphicsPipelineCI.renderPass), pPipeline->graphicsPipelineCI.subpass,
1230fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                subpass_desc->colorAttachmentCount, color_blend_state->attachmentCount,
1231315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                validation_error_map[VALIDATION_ERROR_096005d4]);
1232fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        }
123351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.independentBlend) {
12343d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (pPipeline->attachments.size() > 1) {
123526c548826ff0f83d12c769b51e7d6f76d1265c0eChris Forbes                VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0];
1236c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
123706811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // Quoting the spec: "If [the independent blend] feature is not enabled, the VkPipelineColorBlendAttachmentState
123806811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // settings for all color attachments must be identical." VkPipelineColorBlendAttachmentState contains
123906811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // only attachment state, so memcmp is best suited for the comparison
124006811df0256552cd7da9d7297672af377463fc4aMark Mueller                    if (memcmp(static_cast<const void *>(pAttachments), static_cast<const void *>(&pAttachments[i]),
124106811df0256552cd7da9d7297672af377463fc4aMark Mueller                               sizeof(pAttachments[0]))) {
12423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        skip |=
1243df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1244315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_0f4004ba, "DS",
1245df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "Invalid Pipeline CreateInfo: If independent blend feature not "
1246df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "enabled, all elements of pAttachments must be identical. %s",
1247315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_0f4004ba]);
124806811df0256552cd7da9d7297672af377463fc4aMark Mueller                        break;
1249c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                    }
12505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
12515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
125351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.logicOp && (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) {
12543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
1255df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1256315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_0f4004bc, "DS",
1257f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE. %s",
1258315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_0f4004bc]);
12595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1262a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis    // Ensure the subpass index is valid. If not, then validate_and_capture_pipeline_shader_state
12635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // produces nonsense errors that confuse users. Other layers should already
12645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // emit errors for renderpass being invalid.
12659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto renderPass = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass);
1266fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    if (renderPass && pPipeline->graphicsPipelineCI.subpass >= renderPass->createInfo.subpassCount) {
12673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1268315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005ee, "DS",
12693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: Subpass index %u "
12703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "is out of range for this renderpass (0..%u). %s",
12713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pPipeline->graphicsPipelineCI.subpass, renderPass->createInfo.subpassCount - 1,
1272315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005ee]);
12735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
127559ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis    if (validate_and_capture_pipeline_shader_state(dev_data, pPipeline)) {
12763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = true;
12775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
127852156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    // Each shader's stage must be unique
127952156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    if (pPipeline->duplicate_shaders) {
128052156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        for (uint32_t stage = VK_SHADER_STAGE_VERTEX_BIT; stage & VK_SHADER_STAGE_ALL_GRAPHICS; stage <<= 1) {
128152156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            if (pPipeline->duplicate_shaders & stage) {
12829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
12839b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
12849b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Invalid Pipeline CreateInfo State: Multiple shaders provided for stage %s",
12859b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                string_VkShaderStageFlagBits(VkShaderStageFlagBits(stage)));
128652156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            }
128752156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        }
128852156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    }
12895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VS is required
12905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
1291315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1292315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005ae, "DS",
1293315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "Invalid Pipeline CreateInfo State: Vertex Shader required. %s",
1294315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005ae]);
12955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Either both or neither TC/TE shaders should be defined
12973067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    bool has_control = (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0;
12983067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    bool has_eval = (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0;
12993067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    if (has_control && !has_eval) {
13003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1301315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005b2, "DS",
13023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
1303315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005b2]);
1304f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
13053067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    if (!has_control && has_eval) {
13063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1307315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005b4, "DS",
13083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
1309315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005b4]);
13105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Compute shaders should be specified independent of Gfx shaders
1312f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) {
13133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1314315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005b0, "DS",
13153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline. %s",
1316315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005b0]);
13175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
13195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Mismatching primitive topology and tessellation fails graphics pipeline creation.
13203067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    if (has_control && has_eval &&
1321ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        (!pPipeline->graphicsPipelineCI.pInputAssemblyState ||
1322ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         pPipeline->graphicsPipelineCI.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
13233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1324315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005c0, "DS",
13253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: "
13263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
13273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "topology for tessellation pipelines. %s",
1328315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005c0]);
13295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1330ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pInputAssemblyState &&
1331ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        pPipeline->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
13323067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton        if (!has_control || !has_eval) {
13333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1334315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005c2, "DS",
13353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Invalid Pipeline CreateInfo State: "
13363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
13373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "topology is only valid for tessellation pipelines. %s",
1338315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_096005c2]);
13395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1341f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
13426b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen    // If a rasterization state is provided...
1343a27508babf63d50aea75883a3702979193c23683Mark Young    if (pPipeline->graphicsPipelineCI.pRasterizationState) {
13446b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // Make sure that the line width conforms to the HW.
1345a27508babf63d50aea75883a3702979193c23683Mark Young        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_LINE_WIDTH)) {
13469b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip |=
13479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                verifyLineWidth(dev_data, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, kVulkanObjectTypePipeline,
13489b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), pPipeline->graphicsPipelineCI.pRasterizationState->lineWidth);
1349a27508babf63d50aea75883a3702979193c23683Mark Young        }
13505dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes
135158c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski        if ((pPipeline->graphicsPipelineCI.pRasterizationState->depthClampEnable == VK_TRUE) &&
135258c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski            (!dev_data->enabled_features.depthClamp)) {
13533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1354315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_1020061c, "DS",
13553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCreateGraphicsPipelines(): the depthClamp device feature is disabled: the depthClampEnable "
13563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "member of the VkPipelineRasterizationStateCreateInfo structure must be set to VK_FALSE. %s",
1357315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1020061c]);
135858c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski        }
135958c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski
1360434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_BIAS) &&
1361434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            (pPipeline->graphicsPipelineCI.pRasterizationState->depthBiasClamp != 0.0) &&
1362434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            (!dev_data->enabled_features.depthBiasClamp)) {
13633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
13649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
13653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCreateGraphicsPipelines(): the depthBiasClamp device feature is disabled: the depthBiasClamp "
13663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "member of the VkPipelineRasterizationStateCreateInfo structure must be set to 0.0 unless the "
13673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "VK_DYNAMIC_STATE_DEPTH_BIAS dynamic state is enabled");
1368434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
1369434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski
13706b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // If rasterization is enabled...
13716b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        if (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE) {
13726b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            auto subpass_desc = renderPass ? &renderPass->createInfo.pSubpasses[pPipeline->graphicsPipelineCI.subpass] : nullptr;
13736b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
1374148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski            if ((pPipeline->graphicsPipelineCI.pMultisampleState->alphaToOneEnable == VK_TRUE) &&
1375148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski                (!dev_data->enabled_features.alphaToOne)) {
13763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1377315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_10000622, "DS",
13783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "vkCreateGraphicsPipelines(): the alphaToOne device feature is disabled: the alphaToOneEnable "
13793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "member of the VkPipelineMultisampleStateCreateInfo structure must be set to VK_FALSE. %s",
1380315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_10000622]);
1381148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski            }
1382148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski
13836b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            // If subpass uses a depth/stencil attachment, pDepthStencilState must be a pointer to a valid structure
13846b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            if (subpass_desc && subpass_desc->pDepthStencilAttachment &&
13856b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
13866b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                if (!pPipeline->graphicsPipelineCI.pDepthStencilState) {
13873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1388315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005e0, "DS",
13893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Invalid Pipeline CreateInfo State: pDepthStencilState is NULL when rasterization is "
13903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "enabled and subpass uses a depth/stencil attachment. %s",
1391315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_096005e0]);
13929580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski
13939580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                } else if ((pPipeline->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE) &&
13949580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                           (!dev_data->enabled_features.depthBounds)) {
13953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
1396df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
13979b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
13989580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                        "vkCreateGraphicsPipelines(): the depthBounds device feature is disabled: the depthBoundsTestEnable "
13999580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                        "member of the VkPipelineDepthStencilStateCreateInfo structure must be set to VK_FALSE.");
14006b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                }
14015dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes            }
1402326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen
1403326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            // If subpass uses color attachments, pColorBlendState must be valid pointer
1404326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            if (subpass_desc) {
1405326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                uint32_t color_attachment_count = 0;
1406326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; ++i) {
1407326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    if (subpass_desc->pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
1408326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                        ++color_attachment_count;
1409326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    }
1410326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
1411326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                if (color_attachment_count > 0 && pPipeline->graphicsPipelineCI.pColorBlendState == nullptr) {
14123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1413315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005e2, "DS",
14143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Invalid Pipeline CreateInfo State: pColorBlendState is NULL when rasterization is "
14153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "enabled and subpass uses color attachments. %s",
1416315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_096005e2]);
1417326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
1418326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            }
14195dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes        }
14205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14216b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
14223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
14235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free the Pipeline nodes
142651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePipelines(layer_data *dev_data) {
142751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->pipelineMap.size() <= 0) return;
142851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto &pipe_map_pair : dev_data->pipelineMap) {
1429ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        delete pipe_map_pair.second;
14305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
143151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->pipelineMap.clear();
14325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Block of code at start here specifically for managing/tracking DSs
14355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Pool node ptr for specified pool or else NULL
14379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDESCRIPTOR_POOL_STATE *GetDescriptorPoolState(const layer_data *dev_data, const VkDescriptorPool pool) {
1438bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    auto pool_it = dev_data->descriptorPoolMap.find(pool);
1439bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    if (pool_it == dev_data->descriptorPoolMap.end()) {
14405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
14415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1442bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    return pool_it->second;
14435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
14465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// func_str is the name of the calling function
1447e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return false if no errors occur
1448e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
14490dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlisstatic bool validateIdleDescriptorSet(const layer_data *dev_data, VkDescriptorSet set, std::string func_str) {
1450cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.idle_descriptor_set) return false;
14513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
14520dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    auto set_node = dev_data->setMap.find(set);
14530dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    if (set_node == dev_data->setMap.end()) {
14543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
14559b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
14563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.", func_str.c_str(),
14579b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(set));
14585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
14591c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis        // TODO : This covers various error cases so should pass error enum into this function and use passed in enum here
14605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (set_node->second->in_use.load()) {
14613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
1462315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(set), __LINE__, VALIDATION_ERROR_2860026a, "DS",
14633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that is in use by a command buffer. %s",
1464315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            func_str.c_str(), HandleToUint64(set), validation_error_map[VALIDATION_ERROR_2860026a]);
14655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
14685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1469f80bf38f4fb3f177b3e1be11b7b1c5edcdbf7d9bChris Forbes
1470e6651096ed8f07840447783c66827cc16d659a49Tobin Ehlis// Remove set from setMap and delete the set
14719dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlisstatic void freeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
14729dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    dev_data->setMap.erase(descriptor_set->GetSet());
14739dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    delete descriptor_set;
14749dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis}
14755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all DS Pools including their Sets & related sub-structs
14765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
147751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePools(layer_data *dev_data) {
1478ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson    for (auto ii = dev_data->descriptorPoolMap.begin(); ii != dev_data->descriptorPoolMap.end();) {
1479c5f47f0a54e14c47d402aeabc6498d981ecda9ccTobin Ehlis        // Remove this pools' sets from setMap and delete them
1480ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson        for (auto ds : ii->second->sets) {
148151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            freeDescriptorSet(dev_data, ds);
14825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
1483ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson        ii->second->sets.clear();
1484ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson        delete ii->second;
1485ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson        ii = dev_data->descriptorPoolMap.erase(ii);
14865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
148951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void clearDescriptorPool(layer_data *dev_data, const VkDevice device, const VkDescriptorPool pool,
14905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                VkDescriptorPoolResetFlags flags) {
14919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pPool = GetDescriptorPoolState(dev_data, pool);
1492de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // TODO: validate flags
1493de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // For every set off of this pool, clear it, remove from setMap, and free cvdescriptorset::DescriptorSet
1494de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (auto ds : pPool->sets) {
149551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        freeDescriptorSet(dev_data, ds);
1496de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    }
1497de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->sets.clear();
1498de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // Reset available count for each type and available sets for this pool
1499de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
1500de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis        pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
15015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1502de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->availableSets = pPool->maxSets;
15035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For given CB object, fetch associated CB Node from map
15069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *dev_data, const VkCommandBuffer cb) {
150751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->commandBufferMap.find(cb);
150851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->commandBufferMap.end()) {
15095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
15105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15115121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbes    return it->second;
15125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
151429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis// If a renderpass is active, verify that the given command type is appropriate for current subpass state
151529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlisbool ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
1516cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pCB->activeRenderPass) return false;
15173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1518d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis    if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS &&
1519d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis        (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS)) {
15203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
15219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
15223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Commands cannot be called in a subpass using secondary command buffers.");
15235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) {
15243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
15259b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
15263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdExecuteCommands() cannot be called in a subpass using inline commands.");
15275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
15295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1531baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardtbool ValidateCmdQueueFlags(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const char *caller_name, VkQueueFlags required_flags,
1532baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           UNIQUE_VALIDATION_ERROR_CODE error_code) {
1533baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    auto pool = GetCommandPoolNode(dev_data, cb_node->createInfo.commandPool);
1534baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    if (pool) {
1535baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        VkQueueFlags queue_flags = dev_data->phys_dev_properties.queue_family_properties[pool->queueFamilyIndex].queueFlags;
1536baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        if (!(required_flags & queue_flags)) {
1537baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            string required_flags_string;
1538baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            for (auto flag : {VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT}) {
1539baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                if (flag & required_flags) {
1540baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    if (required_flags_string.size()) {
1541baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                        required_flags_string += " or ";
1542baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    }
1543baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    required_flags_string += string_VkQueueFlagBits(flag);
1544baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                }
1545baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            }
1546baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
15479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(cb_node->commandBuffer), __LINE__, error_code, "DS",
1548baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           "Cannot call %s on a command buffer allocated from a pool without %s capabilities. %s.", caller_name,
1549baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           required_flags_string.c_str(), validation_error_map[error_code]);
1550baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        }
1551baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    }
15525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
15535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1555d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbesstatic char const * GetCauseStr(VK_OBJECT obj) {
1556d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes    if (obj.type == kVulkanObjectTypeDescriptorSet)
1557d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes        return "destroyed or updated";
1558d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes    if (obj.type == kVulkanObjectTypeCommandBuffer)
1559d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes        return "destroyed or rerecorded";
1560d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes    return "destroyed";
1561d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes}
1562d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes
1563ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinskistatic bool ReportInvalidCommandBuffer(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source) {
1564ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    bool skip = false;
1565ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    for (auto obj : cb_state->broken_bindings) {
15667a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        const char *type_str = object_string[obj.type];
1567d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes        const char *cause_str = GetCauseStr(obj);
1568ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
15699b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(cb_state->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
1570ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        "You are adding %s to command buffer 0x%p that is invalid because bound %s 0x%" PRIxLEAST64 " was %s.",
1571ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        call_source, cb_state->commandBuffer, type_str, obj.handle, cause_str);
1572ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    }
1573ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    return skip;
1574ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski}
1575ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
1576623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Validate the given command being added to the specified cmd buffer, flagging errors if CB is not in the recording state or if
1577623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// there's an issue with the Cmd ordering
1578946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskibool ValidateCmd(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd, const char *caller_name) {
157933f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes    switch (cb_state->state) {
158033f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        case CB_RECORDING:
158133f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return ValidateCmdSubpassState(dev_data, cb_state, cmd);
158233f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes
158333f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        case CB_INVALID:
158433f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return ReportInvalidCommandBuffer(dev_data, cb_state, caller_name);
158533f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes
158633f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        default:
158733f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
15889b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS",
158933f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes                           "You must call vkBeginCommandBuffer() before this call to %s", caller_name);
15905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
159229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis
15931ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlisvoid UpdateCmdBufferLastCmd(GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd) {
159429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    if (cb_state->state == CB_RECORDING) {
159529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        cb_state->last_cmd = cmd;
159629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    }
159729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis}
15987e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For given object struct return a ptr of BASE_NODE type for its wrapping struct
15997e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin EhlisBASE_NODE *GetStateStructPtrFromObject(layer_data *dev_data, VK_OBJECT object_struct) {
16007e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_ptr = nullptr;
16017e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    switch (object_struct.type) {
1602ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDescriptorSet: {
16039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(object_struct.handle));
1604cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1605cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1606ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeSampler: {
16079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSamplerState(dev_data, reinterpret_cast<VkSampler &>(object_struct.handle));
1608cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1609cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1610ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeQueryPool: {
16119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(object_struct.handle));
1612cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1613cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1614ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypePipeline: {
1615cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getPipelineState(dev_data, reinterpret_cast<VkPipeline &>(object_struct.handle));
1616cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1617cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1618ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeBuffer: {
16199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object_struct.handle));
1620cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1621cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1622ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeBufferView: {
16239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(object_struct.handle));
1624cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1625cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1626ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeImage: {
16279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageState(dev_data, reinterpret_cast<VkImage &>(object_struct.handle));
1628cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1629cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1630ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeImageView: {
16319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageViewState(dev_data, reinterpret_cast<VkImageView &>(object_struct.handle));
1632cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1633cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1634ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeEvent: {
16359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetEventNode(dev_data, reinterpret_cast<VkEvent &>(object_struct.handle));
1636cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1637cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1638ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDescriptorPool: {
16399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(object_struct.handle));
1640cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1641cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1642ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeCommandPool: {
16439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(object_struct.handle));
1644cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1645cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1646ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeFramebuffer: {
16479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(object_struct.handle));
1648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1649cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1650ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeRenderPass: {
16519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(object_struct.handle));
1652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1653cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1654ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDeviceMemory: {
16559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(object_struct.handle));
1656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1657cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1658cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1659cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO : Any other objects to be handled here?
1660cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            assert(0);
1661cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1662bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis    }
16637e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    return base_ptr;
16647e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
16657e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis
16667e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// Tie the VK_OBJECT to the cmd buffer which includes:
16677e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add object_binding to cmd buffer
16687e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add cb_binding to object
16697e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void addCommandBufferBinding(std::unordered_set<GLOBAL_CB_NODE *> *cb_bindings, VK_OBJECT obj, GLOBAL_CB_NODE *cb_node) {
16707e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_bindings->insert(cb_node);
16717e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_node->object_bindings.insert(obj);
16727e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
16737e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For a given object, if cb_node is in that objects cb_bindings, remove cb_node
16747e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void removeCommandBufferBinding(layer_data *dev_data, VK_OBJECT const *object, GLOBAL_CB_NODE *cb_node) {
16757e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_obj = GetStateStructPtrFromObject(dev_data, *object);
1676cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (base_obj) base_obj->cb_bindings.erase(cb_node);
1677bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis}
16785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Reset the command buffer state
16795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Maintain the createInfo and set state to CB_NEW, but clear all other state
1680400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlisstatic void resetCB(layer_data *dev_data, const VkCommandBuffer cb) {
1681400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis    GLOBAL_CB_NODE *pCB = dev_data->commandBufferMap[cb];
16825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
1683b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        pCB->in_use.store(0);
1684347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        pCB->last_cmd = CMD_NONE;
16855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Reset CB state (note that createInfo is not cleared)
16865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->commandBuffer = cb;
16875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
16885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
1689b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes        pCB->hasDrawCmd = false;
16905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->state = CB_NEW;
16915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->submitCount = 0;
16925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status = 0;
1693b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->viewportMask = 0;
1694b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->scissorMask = 0;
169593c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
169672d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
169772d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            pCB->lastBound[i].reset();
169872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        }
169993c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
17005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo));
1701ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        pCB->activeRenderPass = nullptr;
17025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE;
17035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpass = 0;
1704e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        pCB->broken_bindings.clear();
17055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEvents.clear();
17065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.clear();
1707c7e6bc41aa9c6e5a677b138b9459b252cd3bedf2Mark Lobodzinski        pCB->writeEventsBeforeWait.clear();
17085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEventsBeforeQueryReset.clear();
17095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->queryToStateMap.clear();
17105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.clear();
17115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->startedQueries.clear();
17125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->imageLayoutMap.clear();
17135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->eventToStageMap.clear();
17145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->drawData.clear();
17155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.clear();
171658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        pCB->vertex_buffer_used = false;
17175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->primaryCommandBuffer = VK_NULL_HANDLE;
17181a3660584634742a3297915c94768d73f360e794Chris Forbes        // If secondary, invalidate any primary command buffer that may call us.
17191a3660584634742a3297915c94768d73f360e794Chris Forbes        if (pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {
17201a3660584634742a3297915c94768d73f360e794Chris Forbes            invalidateCommandBuffers(dev_data,
17211a3660584634742a3297915c94768d73f360e794Chris Forbes                                     pCB->linkedCommandBuffers,
17221a3660584634742a3297915c94768d73f360e794Chris Forbes                                     {HandleToUint64(cb), kVulkanObjectTypeCommandBuffer});
17231a3660584634742a3297915c94768d73f360e794Chris Forbes        }
17241a3660584634742a3297915c94768d73f360e794Chris Forbes
17251a3660584634742a3297915c94768d73f360e794Chris Forbes        // Remove reverse command buffer links.
17261a3660584634742a3297915c94768d73f360e794Chris Forbes        for (auto pSubCB : pCB->linkedCommandBuffers) {
17271a3660584634742a3297915c94768d73f360e794Chris Forbes            pSubCB->linkedCommandBuffers.erase(pCB);
17281a3660584634742a3297915c94768d73f360e794Chris Forbes        }
17291a3660584634742a3297915c94768d73f360e794Chris Forbes        pCB->linkedCommandBuffers.clear();
17307a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateImages.clear();
17317a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateBuffers.clear();
1732400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, pCB);
1733b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.clear();
1734d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.clear();
173593c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
1736bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        // Remove object bindings
1737bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        for (auto obj : pCB->object_bindings) {
1738bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis            removeCommandBufferBinding(dev_data, &obj, pCB);
1739bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        }
1740a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        pCB->object_bindings.clear();
174193c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        // Remove this cmdBuffer's reference from each FrameBuffer's CB ref list
174293c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        for (auto framebuffer : pCB->framebuffers) {
17439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
1744cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(pCB);
174593c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        }
174693c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        pCB->framebuffers.clear();
17477003b38da5cc27a063af3c45080f3a35438283eeTobin Ehlis        pCB->activeFramebuffer = VK_NULL_HANDLE;
17485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Set PSO-related status bits for CB, including dynamic state set via PSO
17524c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe) {
17535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Account for any dynamic state not set via this PSO
1754ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (!pPipe->graphicsPipelineCI.pDynamicState ||
1755cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        !pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount) {  // All state is static
17564052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        pCB->status |= CBSTATUS_ALL_STATE_SET;
17575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
17585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // First consider all state on
17595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Then unset any state that's noted as dynamic in PSO
17605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Finally OR that into CB statemask
17614052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        CBStatusFlags psoDynStateMask = CBSTATUS_ALL_STATE_SET;
1762ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        for (uint32_t i = 0; i < pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
1763ca546210846c65808717f8875deae39bd227c240Tobin Ehlis            switch (pPipe->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) {
1764cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_LINE_WIDTH:
1765cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET;
1766cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
1767cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BIAS:
1768cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET;
1769cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
1770cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
1771cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_BLEND_CONSTANTS_SET;
1772cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
1773cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
1774cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET;
1775cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
1776cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
1777cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET;
1778cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
1779cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
1780cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET;
1781cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
1782cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
1783cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET;
1784cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
1785cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
1786cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // TODO : Flag error here
1787cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
17885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= psoDynStateMask;
17915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1794623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Flags validation error if the associated call is made inside a render pass. The apiName routine should ONLY be called outside a
1795623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// render pass.
179651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool insideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
1797e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool inside = false;
17985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass) {
179951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        inside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
18009b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                         HandleToUint64(pCB->commandBuffer), __LINE__, msgCode, "DS",
1801ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         "%s: It is invalid to issue this call inside an active render pass (0x%" PRIxLEAST64 "). %s", apiName,
18029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                         HandleToUint64(pCB->activeRenderPass->renderPass), validation_error_map[msgCode]);
18035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
18045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return inside;
18055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Flags validation error if the associated call is made outside a render pass. The apiName
18085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// routine should ONLY be called inside a render pass.
180951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool outsideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
1810e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool outside = false;
18115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
18125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
18135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
181451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        outside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
18159b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                          HandleToUint64(pCB->commandBuffer), __LINE__, msgCode, "DS",
1816ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          "%s: This call must be issued inside an active render pass. %s", apiName, validation_error_map[msgCode]);
18175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
18185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return outside;
18195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1821f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic void init_core_validation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
1822b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
18235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18257a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis// For the given ValidationCheck enum, set all relevant instance disabled flags to true
18267a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlisvoid SetDisabledFlags(instance_layer_data *instance_data, VkValidationFlagsEXT *val_flags_struct) {
18277a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    for (uint32_t i = 0; i < val_flags_struct->disabledValidationCheckCount; ++i) {
18287a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        switch (val_flags_struct->pDisabledValidationChecks[i]) {
182959ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis            case VK_VALIDATION_CHECK_SHADERS_EXT:
183059ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis                instance_data->disabled.shader_validation = true;
183159ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis                break;
18327a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            case VK_VALIDATION_CHECK_ALL_EXT:
18337a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                // Set all disabled flags to true
18347a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                instance_data->disabled.SetAll(true);
18357a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                break;
18367a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            default:
18377a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                break;
18387a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        }
18397a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    }
18407a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis}
18417a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis
1842bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
1843bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkInstance *pInstance) {
18445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
18455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
18475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
18485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
1849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
18505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
18525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
18535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
1855cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (result != VK_SUCCESS) return result;
18565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
185756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
185856a5ba3e60a723781945959ffc10e2e215350de5Chia-I Wu    instance_data->instance = *pInstance;
18599172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
18609172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->report_data = debug_report_create_instance(
18619172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
18620cf009a4e2a5c22e4645f343c7a998f188a22015Chris Forbes    instance_data->extensions.InitFromInstanceCreateInfo(pCreateInfo);
1863b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    init_core_validation(instance_data, pAllocator);
1864825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski
18655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
18667a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    // Parse any pNext chains
18677a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    if (pCreateInfo->pNext) {
18687a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        GENERIC_HEADER *struct_header = (GENERIC_HEADER *)pCreateInfo->pNext;
18697a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        while (struct_header) {
18707a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            // Check for VkValidationFlagsExt
18717a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            if (VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT == struct_header->sType) {
18727a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                SetDisabledFlags(instance_data, (VkValidationFlagsEXT *)struct_header);
18737a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            }
18747a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            struct_header = (GENERIC_HEADER *)struct_header->pNext;
18757a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        }
18767a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    }
18775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
18795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
188125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Hook DestroyInstance to remove tableInstanceMap entry
188289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
18835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
18845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(instance);
18855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TBD: Need any locking this early, in case this function is called at the
18865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // same time by more than one thread?
188756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
18889172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
18895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1890b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
18915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Clean up logging callback, if any
18929172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    while (instance_data->logging_callback.size() > 0) {
18939172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
18949172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
18959172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        instance_data->logging_callback.pop_back();
18965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
18975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18989172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_debug_report_destroy_instance(instance_data->report_data);
1899d27b109eaf4da0a5514dc2ae2f3dd6a76976ba0dGabríel Arthúr Pétursson    FreeLayerDataPtr(key, instance_layer_data_map);
19005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
19015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19025770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstatic bool ValidatePhysicalDeviceQueueFamily(instance_layer_data *instance_data, const PHYSICAL_DEVICE_STATE *pd_state,
19035770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                              uint32_t requested_queue_family, int32_t err_code, const char *cmd_name,
19045770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                              const char *queue_family_var_name, const char *vu_note = nullptr) {
19053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
19065770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
19075770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (!vu_note) vu_note = validation_error_map[err_code];
19085770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
19095770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    const char *conditional_ext_cmd =
1910d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        instance_data->extensions.vk_khr_get_physical_device_properties_2 ? "or vkGetPhysicalDeviceQueueFamilyProperties2KHR" : "";
19115770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
19125770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::string count_note = (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState)
19135770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                 ? "the pQueueFamilyPropertyCount was never obtained"
19145770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                 : "i.e. is not less than " + std::to_string(pd_state->queue_family_count);
19155770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
19165770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (requested_queue_family >= pd_state->queue_family_count) {
19173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
19189b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pd_state->phys_device), __LINE__, err_code, "DL",
19199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "%s: %s (= %" PRIu32
19209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        ") is not less than any previously obtained pQueueFamilyPropertyCount from "
19215770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                        "vkGetPhysicalDeviceQueueFamilyProperties%s (%s). %s",
19225770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                        cmd_name, queue_family_var_name, requested_queue_family, conditional_ext_cmd, count_note.c_str(), vu_note);
19235770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    }
19245770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return skip;
19255770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus}
19265770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
19275770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus// Verify VkDeviceQueueCreateInfos
19285770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstatic bool ValidateDeviceQueueCreateInfos(instance_layer_data *instance_data, const PHYSICAL_DEVICE_STATE *pd_state,
19295770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                           uint32_t info_count, const VkDeviceQueueCreateInfo *infos) {
19305770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    bool skip = false;
19315770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
19325770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    for (uint32_t i = 0; i < info_count; ++i) {
19335770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        const auto requested_queue_family = infos[i].queueFamilyIndex;
19345770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
19355770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        // Verify that requested queue family is known to be valid at this point in time
19365770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        std::string queue_family_var_name = "pCreateInfo->pQueueCreateInfos[" + std::to_string(i) + "].queueFamilyIndex";
1937315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, requested_queue_family, VALIDATION_ERROR_06c002fa,
19385770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                  "vkCreateDevice", queue_family_var_name.c_str());
19395770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
19405770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        // Verify that requested  queue count of queue family is known to be valid at this point in time
19415770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        if (requested_queue_family < pd_state->queue_family_count) {
19425770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            const auto requested_queue_count = infos[i].queueCount;
19435770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            const auto queue_family_props_count = pd_state->queue_family_properties.size();
19445770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            const bool queue_family_has_props = requested_queue_family < queue_family_props_count;
1945d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski            const char *conditional_ext_cmd = instance_data->extensions.vk_khr_get_physical_device_properties_2
19465770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                  ? "or vkGetPhysicalDeviceQueueFamilyProperties2KHR"
19475770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                  : "";
19485770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            std::string count_note =
19495770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                !queue_family_has_props
19505770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                    ? "the pQueueFamilyProperties[" + std::to_string(requested_queue_family) + "] was never obtained"
19515770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                    : "i.e. is not less than or equal to " +
19525770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                          std::to_string(pd_state->queue_family_properties[requested_queue_family].queueCount);
19535770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
19545770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            if (!queue_family_has_props ||
19555770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                requested_queue_count > pd_state->queue_family_properties[requested_queue_family].queueCount) {
19563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
19579b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(pd_state->phys_device), __LINE__,
1958315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                VALIDATION_ERROR_06c002fc, "DL",
19599b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkCreateDevice: pCreateInfo->pQueueCreateInfos[%" PRIu32 "].queueCount (=%" PRIu32
19609b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                ") is not "
19615770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                "less than or equal to available queue count for this "
19629b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "pCreateInfo->pQueueCreateInfos[%" PRIu32 "].queueFamilyIndex} (=%" PRIu32
19639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                ") obtained previously "
19645770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                "from vkGetPhysicalDeviceQueueFamilyProperties%s (%s). %s",
19655770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                i, requested_queue_count, i, requested_queue_family, conditional_ext_cmd, count_note.c_str(),
1966315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_06c002fc]);
1967838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            }
1968838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        }
1969838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    }
19705770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
19713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
1972838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski}
1973838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski
1974f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski// Verify that features have been queried and that they are available
19755770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstatic bool ValidateRequestedFeatures(instance_layer_data *instance_data, const PHYSICAL_DEVICE_STATE *pd_state,
1976bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                      const VkPhysicalDeviceFeatures *requested_features) {
19773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1978f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
19795770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    const VkBool32 *actual = reinterpret_cast<const VkBool32 *>(&pd_state->features);
1980825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski    const VkBool32 *requested = reinterpret_cast<const VkBool32 *>(requested_features);
1981f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // TODO : This is a nice, compact way to loop through struct, but a bad way to report issues
1982f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  Need to provide the struct member name with the issue. To do that seems like we'll
1983f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  have to loop through each struct member which should be done w/ codegen to keep in synch.
1984f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t errors = 0;
1985f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t total_bools = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
1986f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    for (uint32_t i = 0; i < total_bools; i++) {
1987f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        if (requested[i] > actual[i]) {
1988f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            // TODO: Add index to struct member name helper to be able to include a feature name
19895770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
19905770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
19913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "While calling vkCreateDevice(), requesting feature #%u in VkPhysicalDeviceFeatures struct, "
19923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "which is not available on this device.",
19933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            i);
1994f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            errors++;
1995f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        }
1996f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
19975770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (errors && (UNCALLED == pd_state->vkGetPhysicalDeviceFeaturesState)) {
1998f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // If user didn't request features, notify them that they should
1999f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // TODO: Verify this against the spec. I believe this is an invalid use of the API and should return an error
20005770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
20015770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                        0, __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
20023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "You requested features that are unavailable on this device. You should first query feature "
20033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "availability by calling vkGetPhysicalDeviceFeatures().");
2004f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
20053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
2006f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
2007f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
200889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
200989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
20103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
20115770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
2012f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
20135770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::unique_lock<std::mutex> lock(global_lock);
2014f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    auto pd_state = GetPhysicalDeviceState(instance_data, gpu);
2015f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
2016f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // TODO: object_tracker should perhaps do this instead
2017f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    //       and it does not seem to currently work anyway -- the loader just crashes before this point
2018f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (!GetPhysicalDeviceState(instance_data, gpu)) {
2019f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
2020f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                        0, __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
2021f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                        "Invalid call to vkCreateDevice() w/o first calling vkEnumeratePhysicalDevices().");
2022f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    }
2023f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
2024f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // Check that any requested features are available
2025f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    if (pCreateInfo->pEnabledFeatures) {
20265770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        skip |= ValidateRequestedFeatures(instance_data, pd_state, pCreateInfo->pEnabledFeatures);
2027f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
20285770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    skip |=
20295770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        ValidateDeviceQueueCreateInfos(instance_data, pd_state, pCreateInfo->queueCreateInfoCount, pCreateInfo->pQueueCreateInfos);
2030f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
20315770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
20321d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller
20335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
20345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
20365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
20375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
203856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice");
20395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (fpCreateDevice == NULL) {
20405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_INITIALIZATION_FAILED;
20415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
20445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
20455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20465770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.unlock();
20475770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
20485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
20495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result != VK_SUCCESS) {
20505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return result;
20515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20535770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.lock();
205456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
20555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
205656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->instance_data = instance_data;
20575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Setup device dispatch table
205856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
205956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->device = *pDevice;
2060ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    // Save PhysicalDevice handle
206156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->physical_device = gpu;
20625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
206356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->report_data = layer_debug_report_create_device(instance_data->report_data, *pDevice);
2064a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski    device_data->extensions.InitFromDeviceCreateInfo(&instance_data->extensions, pCreateInfo);
2065d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski
20665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Get physical device limits for this device
206756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &(device_data->phys_dev_properties.properties));
20685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t count;
206956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
207056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->phys_dev_properties.queue_family_properties.resize(count);
207156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(
207256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        gpu, &count, &device_data->phys_dev_properties.queue_family_properties[0]);
20735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO: device limits should make sure these are compatible
20745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCreateInfo->pEnabledFeatures) {
207556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        device_data->enabled_features = *pCreateInfo->pEnabledFeatures;
20765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
207756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        memset(&device_data->enabled_features, 0, sizeof(VkPhysicalDeviceFeatures));
20785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2079e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    // Store physical device properties and physical device mem limits into device layer_data structs
208056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceMemoryProperties(gpu, &device_data->phys_dev_mem_props);
208156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &device_data->phys_dev_props);
2082b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
20835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
20855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
20875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// prototype
209089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
20915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
20925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(device);
209356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(key, layer_data_map);
20945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Free all the memory
2095b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
20965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePipelines(dev_data);
2097fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    dev_data->renderPassMap.clear();
20989b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes    for (auto ii = dev_data->commandBufferMap.begin(); ii != dev_data->commandBufferMap.end(); ++ii) {
20999b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes        delete (*ii).second;
21009b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes    }
21019b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes    dev_data->commandBufferMap.clear();
2102f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // This will also delete all sets in the pool & remove them from setMap
21035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePools(dev_data);
2104f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // All sets should be removed
2105f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    assert(dev_data->setMap.empty());
2106fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis    dev_data->descriptorSetLayoutMap.clear();
21075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageViewMap.clear();
21085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageMap.clear();
21095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageSubresourceMap.clear();
21105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageLayoutMap.clear();
21115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferViewMap.clear();
21125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferMap.clear();
21131344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    // Queues persist until device is destroyed
21141344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    dev_data->queueMap.clear();
21155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Report any memory leaks
21165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_debug_report_destroy_device(device);
2117b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
21185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if DISPATCH_MAP_DEBUG
2120414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller    fprintf(stderr, "Device: 0x%p, key: 0x%p\n", device, key);
21215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
2122d27b109eaf4da0a5514dc2ae2f3dd6a76976ba0dGabríel Arthúr Pétursson
2123d27b109eaf4da0a5514dc2ae2f3dd6a76976ba0dGabríel Arthúr Pétursson    dev_data->dispatch_table.DestroyDevice(device, pAllocator);
2124d27b109eaf4da0a5514dc2ae2f3dd6a76976ba0dGabríel Arthúr Pétursson    FreeLayerDataPtr(key, layer_data_map);
21255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
21285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2129208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis// For given stage mask, if Geometry shader stage is on w/o GS being enabled, report geo_error_id
2130208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis//   and if Tessellation Control or Evaluation shader stages are on w/o TS being enabled, report tess_error_id
2131208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlisstatic bool ValidateStageMaskGsTsEnables(layer_data *dev_data, VkPipelineStageFlags stageMask, const char *caller,
2132208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                         UNIQUE_VALIDATION_ERROR_CODE geo_error_id, UNIQUE_VALIDATION_ERROR_CODE tess_error_id) {
2133208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    bool skip = false;
2134208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.geometryShader && (stageMask & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) {
2135208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2136cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        geo_error_id, "DL",
2137cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT bit set when "
2138cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "device does not have geometryShader feature enabled. %s",
2139208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[geo_error_id]);
2140208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
2141208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.tessellationShader &&
2142208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        (stageMask & (VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT))) {
2143208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2144cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        tess_error_id, "DL",
2145cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT "
2146cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "and/or VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT bit(s) set when device "
2147cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "does not have tessellationShader feature enabled. %s",
2148208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[tess_error_id]);
2149208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
2150208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    return skip;
2151208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis}
2152208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis
2153ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes// Loop through bound objects and increment their in_use counts.
2154ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayesstatic void IncrementBoundObjects(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
2155a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
2156a317e7593a0fe227635fc8241908471acb36c952Chris Forbes        auto base_obj = GetStateStructPtrFromObject(dev_data, obj);
2157ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes        if (base_obj) {
215851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            base_obj->in_use.fetch_add(1);
2159162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis        }
2160a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
2161a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
21625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Track which resources are in-flight by atomically incrementing their "in_use" count
216351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void incrementResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
216451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    cb_node->submitCount++;
21659a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    cb_node->in_use.fetch_add(1);
2166a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
2167a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // First Increment for all "generic" objects bound to cmd buffer, followed by special-case objects below
2168ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes    IncrementBoundObjects(dev_data, cb_node);
2169a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
2170a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
2171a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  should then be flagged prior to calling this function
21729a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto drawDataElement : cb_node->drawData) {
21735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto buffer : drawDataElement.buffers) {
21749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto buffer_state = GetBufferState(dev_data, buffer);
217551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (buffer_state) {
21765cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                buffer_state->in_use.fetch_add(1);
21775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
21785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
21795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
21809a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto event : cb_node->writeEventsBeforeWait) {
21819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
2182cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (event_state) event_state->write_in_use++;
2183c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
21845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2186b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Note: This function assumes that the global lock is held by the calling thread.
2187b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// For the given queue, verify the queue state up to the given seq number.
2188b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Currently the only check is to make sure that if there are events to be waited on prior to
2189b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis//  a QueryReset, make sure that all such events have been signalled.
2190d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbesstatic bool VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *initial_queue, uint64_t initial_seq) {
2191b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    bool skip = false;
2192d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
2193d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    // sequence number we want to validate up to, per queue
2194d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::unordered_map<QUEUE_STATE *, uint64_t> target_seqs { { initial_queue, initial_seq } };
2195d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    // sequence number we've completed validation for, per queue
2196d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::unordered_map<QUEUE_STATE *, uint64_t> done_seqs;
2197d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::vector<QUEUE_STATE *> worklist { initial_queue };
2198d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
2199d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    while (worklist.size()) {
2200d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto queue = worklist.back();
2201d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        worklist.pop_back();
2202d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
2203d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto target_seq = target_seqs[queue];
2204d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto seq = std::max(done_seqs[queue], queue->seq);
2205d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto sub_it = queue->submissions.begin() + int(seq - queue->seq);  // seq >= queue->seq
2206d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
2207d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        for (; seq < target_seq; ++sub_it, ++seq) {
2208d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            for (auto &wait : sub_it->waitSemaphores) {
2209d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_queue = GetQueueState(dev_data, wait.queue);
2210d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
2211d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (other_queue == queue)
2212d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    continue;   // semaphores /always/ point backwards, so no point here.
2213d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
2214d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_target_seq = std::max(target_seqs[other_queue], wait.seq);
2215d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_done_seq = std::max(done_seqs[other_queue], other_queue->seq);
2216d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
2217d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // if this wait is for another queue, and covers new sequence
2218d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // numbers beyond what we've already validated, mark the new
2219d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // target seq and (possibly-re)add the queue to the worklist.
2220d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (other_done_seq < other_target_seq) {
2221d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    target_seqs[other_queue] = other_target_seq;
2222d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    worklist.push_back(other_queue);
2223d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                }
2224d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            }
2225d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
2226d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            for (auto cb : sub_it->cbs) {
2227d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto cb_node = GetCBNode(dev_data, cb);
2228d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (cb_node) {
2229d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    for (auto queryEventsPair : cb_node->waitedEventsBeforeQueryReset) {
2230d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                        for (auto event : queryEventsPair.second) {
2231d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                            if (dev_data->eventMap[event].needsSignaled) {
2232d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2233d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS",
2234d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                "Cannot get query results on queryPool 0x%" PRIx64
2235d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                " with index %d which was guarded by unsignaled event 0x%" PRIx64 ".",
22369b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                HandleToUint64(queryEventsPair.first.pool), queryEventsPair.first.index,
22379b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                HandleToUint64(event));
2238d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                            }
2239b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                        }
2240b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    }
2241b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine                }
2242b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine            }
2243b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        }
2244d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
2245d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        // finally mark the point we've now validated this queue to.
2246d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        done_seqs[queue] = seq;
224792b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    }
2248d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
2249b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return skip;
2250b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis}
2251b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis
2252b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// When the given fence is retired, verify outstanding queue operations through the point of the fence
2253b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic bool VerifyQueueStateToFence(layer_data *dev_data, VkFence fence) {
22549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto fence_state = GetFenceNode(dev_data, fence);
2255b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    if (VK_NULL_HANDLE != fence_state->signaler.first) {
22569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        return VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, fence_state->signaler.first), fence_state->signaler.second);
2257b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    }
2258b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return false;
2259b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
22607d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes
2261a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis// Decrement in-use count for objects bound to command buffer
22622f8cbf3b166e175174877a59929902e005953d6dTobin Ehlisstatic void DecrementBoundResources(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
226300e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis    BASE_NODE *base_obj = nullptr;
2264a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
22657e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis        base_obj = GetStateStructPtrFromObject(dev_data, obj);
226600e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        if (base_obj) {
226700e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis            base_obj->in_use.fetch_sub(1);
226800e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        }
2269a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
2270a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
2271da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes
227236c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void RetireWorkOnQueue(layer_data *dev_data, QUEUE_STATE *pQueue, uint64_t seq) {
22739867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unordered_map<VkQueue, uint64_t> otherQueueSeqs;
22749867daedbf52debc77d6568162ee21e071699b80Chris Forbes
22759867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll this queue forward, one submission at a time.
22769867daedbf52debc77d6568162ee21e071699b80Chris Forbes    while (pQueue->seq < seq) {
2277bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &submission = pQueue->submissions.front();
22789867daedbf52debc77d6568162ee21e071699b80Chris Forbes
2279bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &wait : submission.waitSemaphores) {
22809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, wait.semaphore);
2281c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
2282c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
2283c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
2284bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto &lastSeq = otherQueueSeqs[wait.queue];
22859867daedbf52debc77d6568162ee21e071699b80Chris Forbes            lastSeq = std::max(lastSeq, wait.seq);
2286da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes        }
2287cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
2288bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &semaphore : submission.signalSemaphores) {
22899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
2290c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
2291c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
2292c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
22939867daedbf52debc77d6568162ee21e071699b80Chris Forbes        }
2294cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
22959867daedbf52debc77d6568162ee21e071699b80Chris Forbes        for (auto cb : submission.cbs) {
22969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, cb);
2297c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (!cb_node) {
2298c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                continue;
2299c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
2300a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis            // First perform decrement on general case bound objects
23019a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            DecrementBoundResources(dev_data, cb_node);
23029a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto drawDataElement : cb_node->drawData) {
23039867daedbf52debc77d6568162ee21e071699b80Chris Forbes                for (auto buffer : drawDataElement.buffers) {
23049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto buffer_state = GetBufferState(dev_data, buffer);
23055cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                    if (buffer_state) {
23065cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                        buffer_state->in_use.fetch_sub(1);
23079867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
23089867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
2309da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
23109a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto event : cb_node->writeEventsBeforeWait) {
23119867daedbf52debc77d6568162ee21e071699b80Chris Forbes                auto eventNode = dev_data->eventMap.find(event);
23129867daedbf52debc77d6568162ee21e071699b80Chris Forbes                if (eventNode != dev_data->eventMap.end()) {
23139867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    eventNode->second.write_in_use--;
23149867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
23159867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
23169a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto queryStatePair : cb_node->queryToStateMap) {
23179867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->queryToStateMap[queryStatePair.first] = queryStatePair.second;
23189867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
23199a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto eventStagePair : cb_node->eventToStageMap) {
23209867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second;
2321da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
23220a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine
2323a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            cb_node->in_use.fetch_sub(1);
23240a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
23259867daedbf52debc77d6568162ee21e071699b80Chris Forbes
23269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, submission.fence);
23279867daedbf52debc77d6568162ee21e071699b80Chris Forbes        if (pFence) {
23289867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pFence->state = FENCE_RETIRED;
23290a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
23309867daedbf52debc77d6568162ee21e071699b80Chris Forbes
23319867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->submissions.pop_front();
23329867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->seq++;
2333b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
23349867daedbf52debc77d6568162ee21e071699b80Chris Forbes
23359867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll other queues forward to the highest seq we saw a wait for
23369867daedbf52debc77d6568162ee21e071699b80Chris Forbes    for (auto qs : otherQueueSeqs) {
23379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, qs.first), qs.second);
2338d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
23399867daedbf52debc77d6568162ee21e071699b80Chris Forbes}
2340651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
2341651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// Submit a fence to a queue, delimiting previous fences and previous untracked
2342651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// work by it.
234336c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void SubmitFence(QUEUE_STATE *pQueue, FENCE_NODE *pFence, uint64_t submitCount) {
2344cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes    pFence->state = FENCE_INFLIGHT;
23459867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.first = pQueue->queue;
23469867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.second = pQueue->seq + pQueue->submissions.size() + submitCount;
2347b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
2348b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
234951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
23503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
2351a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    if ((pCB->in_use.load() || current_submit_count > 1) &&
23525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
23533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
2354315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        __LINE__, VALIDATION_ERROR_31a0008e, "DS",
23553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Command Buffer 0x%p is already in use and is not marked for simultaneous use. %s", pCB->commandBuffer,
2356315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_31a0008e]);
23575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
23583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
23595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
23605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2361946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskistatic bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source,
23620de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                                       int current_submit_count, UNIQUE_VALIDATION_ERROR_CODE vu_id) {
2363c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    bool skip = false;
2364cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.command_buffer_state) return skip;
23650a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
2366946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if ((cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) &&
2367946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        (cb_state->submitCount + current_submit_count > 1)) {
2368c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
2369c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
2370226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Commandbuffer 0x%p was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT "
2371c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        "set, but has been submitted 0x%" PRIxLEAST64 " times.",
2372946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->commandBuffer, cb_state->submitCount + current_submit_count);
23730a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    }
237494307efee520ad91d5da2ff8f40609b31f05b2efChris Forbes
23755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate that cmd buffers have been updated
2376946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (CB_RECORDED != cb_state->state) {
2377946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (CB_INVALID == cb_state->state) {
2378946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= ReportInvalidCommandBuffer(dev_data, cb_state, call_source);
23790de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski        } else if (CB_NEW == cb_state->state) {
23800de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
23810de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            (uint64_t)(cb_state->commandBuffer), __LINE__, vu_id, "DS",
23820de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "Command buffer 0x%p used in the call to %s is unrecorded and contains no commands. %s",
23830de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            cb_state->commandBuffer, call_source, validation_error_map[vu_id]);
2384cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Flag error for using CB w/o vkEndCommandBuffer() called
2385c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
23869b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS",
2387946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "You must call vkEndCommandBuffer() on command buffer 0x%p before this call to %s!",
2388946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            cb_state->commandBuffer, call_source);
23895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
23905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2391c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    return skip;
23925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
23935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
239451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
23953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
239651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
239751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
239851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
239951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  should then be flagged prior to calling this function
240051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (auto drawDataElement : cb_node->drawData) {
240151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (auto buffer : drawDataElement.buffers) {
240251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto buffer_state = GetBufferState(dev_data, buffer);
240351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (!buffer_state) {
24043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
24059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
24069b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Cannot submit cmd buffer using deleted buffer 0x%" PRIx64 ".", HandleToUint64(buffer));
240751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
240851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
240951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
24103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
241151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
241251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
2413f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski// Check that the queue family index of 'queue' matches one of the entries in pQueueFamilyIndices
2414f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinskibool ValidImageBufferQueue(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const VK_OBJECT *object, VkQueue queue, uint32_t count,
2415f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           const uint32_t *indices) {
2416f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    bool found = false;
2417f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    bool skip = false;
2418f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    auto queue_state = GetQueueState(dev_data, queue);
2419f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    if (queue_state) {
2420f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        for (uint32_t i = 0; i < count; i++) {
2421f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            if (indices[i] == queue_state->queueFamilyIndex) {
2422f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                found = true;
2423f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                break;
2424f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            }
2425f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
2426f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
2427f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        if (!found) {
24289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip = log_msg(
24299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object->type], object->handle, __LINE__,
24309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                DRAWSTATE_INVALID_QUEUE_FAMILY, "DS", "vkQueueSubmit: Command buffer 0x%" PRIxLEAST64 " contains %s 0x%" PRIxLEAST64
24319b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                      " which was not created allowing concurrent access to this queue family %d.",
24329b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(cb_node->commandBuffer), object_string[object->type], object->handle, queue_state->queueFamilyIndex);
2433f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
2434f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    }
2435f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    return skip;
2436f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski}
2437f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
24387bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Validate that queueFamilyIndices of primary command buffers match this queue
24397bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Secondary command buffers were previously validated in vkCmdExecuteCommands().
24407bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinskistatic bool validateQueueFamilyIndices(layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkQueue queue) {
24413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
24429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
24439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
24447bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
2445f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    if (pPool && queue_state) {
2446f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        if (pPool->queueFamilyIndex != queue_state->queueFamilyIndex) {
24473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2448315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_31a00094, "DS",
24493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkQueueSubmit: Primary command buffer 0x%p created in queue family %d is being submitted on queue "
24503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "0x%p from queue family %d. %s",
24513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            pCB->commandBuffer, pPool->queueFamilyIndex, queue, queue_state->queueFamilyIndex,
2452315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_31a00094]);
2453f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
2454f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
2455f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        // Ensure that any bound images or buffers created with SHARING_MODE_CONCURRENT have access to the current queue family
2456f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        for (auto object : pCB->object_bindings) {
24577a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            if (object.type == kVulkanObjectTypeImage) {
2458f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(object.handle));
2459f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                if (image_state && image_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
24603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= ValidImageBufferQueue(dev_data, pCB, &object, queue, image_state->createInfo.queueFamilyIndexCount,
24613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                  image_state->createInfo.pQueueFamilyIndices);
2462f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                }
24637a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            } else if (object.type == kVulkanObjectTypeBuffer) {
2464f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object.handle));
2465f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                if (buffer_state && buffer_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
24663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= ValidImageBufferQueue(dev_data, pCB, &object, queue, buffer_state->createInfo.queueFamilyIndexCount,
24673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                  buffer_state->createInfo.pQueueFamilyIndices);
2468f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                }
2469f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            }
2470f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
24717bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
24727bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
24733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
24747bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski}
24757bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
247651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
24775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Track in-use for resources off of primary and any secondary CBs
24783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
2479a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
2480a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
2481a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // on device
24823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateCommandBufferSimultaneousUse(dev_data, pCB, current_submit_count);
2483a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
24843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateResources(dev_data, pCB);
2485a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
24861a3660584634742a3297915c94768d73f360e794Chris Forbes    for (auto pSubCB : pCB->linkedCommandBuffers) {
248711decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes        skip |= validateResources(dev_data, pSubCB);
24881a3660584634742a3297915c94768d73f360e794Chris Forbes        // TODO: replace with invalidateCommandBuffers() at recording.
248911decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes        if ((pSubCB->primaryCommandBuffer != pCB->commandBuffer) &&
249011decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes            !(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
2491315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
2492315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    __LINE__, VALIDATION_ERROR_31a00092, "DS",
2493315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    "Commandbuffer 0x%p was submitted with secondary buffer 0x%p but that buffer has subsequently been bound to "
2494f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "primary cmd buffer 0x%p and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set. %s",
2495315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    pCB->commandBuffer, pSubCB->commandBuffer, pSubCB->primaryCommandBuffer,
2496315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    validation_error_map[VALIDATION_ERROR_31a00092]);
24975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
24985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2499a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
2500315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= validateCommandBufferState(dev_data, pCB, "vkQueueSubmit()", current_submit_count, VALIDATION_ERROR_31a00090);
2501a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
25023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
25035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
25045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2505bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateFenceForSubmit(layer_data *dev_data, FENCE_NODE *pFence) {
25063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
250781c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
2508651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
2509cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_INFLIGHT) {
2510315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // TODO: opportunities for VALIDATION_ERROR_31a00080, VALIDATION_ERROR_316008b4, VALIDATION_ERROR_16400a0e
25113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
25129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pFence->fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
25139b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Fence 0x%" PRIx64 " is already in use by another submission.", HandleToUint64(pFence->fence));
2514a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
251581c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
2516cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        else if (pFence->state == FENCE_RETIRED) {
2517315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // TODO: opportunities for VALIDATION_ERROR_31a0007e, VALIDATION_ERROR_316008b2, VALIDATION_ERROR_16400a0e
25183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
25199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pFence->fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
25203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Fence 0x%" PRIxLEAST64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
25219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pFence->fence));
2522a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
25235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
252481c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
25253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
252681c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes}
252781c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
252851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void PostCallRecordQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
252951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                      VkFence fence) {
25309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
25319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
2532d7d60cccc862fee2d0b3ad410c5fdcc40ddc83aeChris Forbes
2533651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    // Mark the fence in-use.
2534651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
25359867daedbf52debc77d6568162ee21e071699b80Chris Forbes        SubmitFence(pQueue, pFence, std::max(1u, submitCount));
2536651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    }
2537651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
253851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now process each individual submit
25395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
254051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        std::vector<VkCommandBuffer> cbs;
25415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubmitInfo *submit = &pSubmits[submit_idx];
25429867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<SEMAPHORE_WAIT> semaphore_waits;
25439867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<VkSemaphore> semaphore_signals;
25445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
254551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pWaitSemaphores[i];
254651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
254751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
254851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
254951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
255051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    pSemaphore->in_use.fetch_add(1);
255151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
255251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = VK_NULL_HANDLE;
255351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = false;
255451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
255551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
255651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
255751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pSignalSemaphores[i];
255851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
255951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
256051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = queue;
256151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
256251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = true;
256351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->in_use.fetch_add(1);
256451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                semaphore_signals.push_back(semaphore);
256551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
256651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
256751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
256851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
256951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (cb_node) {
257051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                cbs.push_back(submit->pCommandBuffers[i]);
25711a3660584634742a3297915c94768d73f360e794Chris Forbes                for (auto secondaryCmdBuffer : cb_node->linkedCommandBuffers) {
257211decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes                    cbs.push_back(secondaryCmdBuffer->commandBuffer);
257351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
257451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                UpdateCmdBufImageLayouts(dev_data, cb_node);
257551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                incrementResources(dev_data, cb_node);
25761a3660584634742a3297915c94768d73f360e794Chris Forbes                for (auto secondaryCmdBuffer : cb_node->linkedCommandBuffers) {
257711decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes                    incrementResources(dev_data, secondaryCmdBuffer);
257851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
257951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
258051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
258151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(cbs, semaphore_waits, semaphore_signals,
258251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         submit_idx == submitCount - 1 ? fence : VK_NULL_HANDLE);
258351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
258451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
258551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if (pFence && !submitCount) {
258651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // If no submissions, but just dropping a fence on the end of the queue,
258751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // record an empty submission with just the fence, so we can determine
258851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // its completion.
258951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
259051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         fence);
259151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
259251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
259351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
259451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool PreCallValidateQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
259551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                       VkFence fence) {
259651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    auto pFence = GetFenceNode(dev_data, fence);
25973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = ValidateFenceForSubmit(dev_data, pFence);
25983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
259951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        return true;
260051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
260151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
260251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> signaled_semaphores;
260351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> unsignaled_semaphores;
260451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    vector<VkCommandBuffer> current_cmds;
260551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> localImageLayoutMap = dev_data->imageLayoutMap;
260651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now verify each individual submit
260751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
260851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        const VkSubmitInfo *submit = &pSubmits[submit_idx];
260951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
2610315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= ValidateStageMaskGsTsEnables(dev_data, submit->pWaitDstStageMask[i], "vkQueueSubmit()",
2611315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                 VALIDATION_ERROR_13c00098, VALIDATION_ERROR_13c0009a);
261201a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pWaitSemaphores[i];
26139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
261401a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
261551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (unsignaled_semaphores.count(semaphore) ||
2616440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                    (!(signaled_semaphores.count(semaphore)) && !(pSemaphore->signaled))) {
26173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
26189b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
26193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
26209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore));
262151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                } else {
262251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.erase(semaphore);
262351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.insert(semaphore);
26241344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
26255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
26265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
26275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
262801a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pSignalSemaphores[i];
26299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
263001a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
2631440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                if (signaled_semaphores.count(semaphore) || (!(unsignaled_semaphores.count(semaphore)) && pSemaphore->signaled)) {
26323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
26339b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
26343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Queue 0x%p is signaling semaphore 0x%" PRIx64
26353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " that has already been signaled but not waited on by queue 0x%" PRIx64 ".",
26369b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    queue, HandleToUint64(semaphore), HandleToUint64(pSemaphore->signaler.first));
26371344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
263851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.erase(semaphore);
263951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.insert(semaphore);
26401344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
26410a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine            }
26425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
26435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
26449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
2645d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            if (cb_node) {
26463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateCmdBufImageLayouts(dev_data, cb_node, localImageLayoutMap);
264751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                current_cmds.push_back(submit->pCommandBuffers[i]);
26483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= validatePrimaryCommandBufferState(
264951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    dev_data, cb_node, (int)std::count(current_cmds.begin(), current_cmds.end(), submit->pCommandBuffers[i]));
26503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= validateQueueFamilyIndices(dev_data, cb_node, queue);
265151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
2652ea371fa7c8c57edb4d1436e4570cf54f3fc0463fTobin Ehlis                // Potential early exit here as bad object state may crash in delayed function calls
26533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                if (skip) {
265451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    return true;
265551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
265651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
26571344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                // Call submit-time functions to validate/update state
2658d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->validate_functions) {
26593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function();
26601344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
2661d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->eventUpdates) {
26623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function(queue);
26631344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
2664d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->queryUpdates) {
26653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function(queue);
2666d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
26671344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            }
26685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
26699867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
26703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
267151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
26729867daedbf52debc77d6568162ee21e071699b80Chris Forbes
267351920949f887ce8d3666c73c28ff19a5d8325a37Tony BarbourVKAPI_ATTR VkResult VKAPI_CALL QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
267451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
267551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    std::unique_lock<std::mutex> lock(global_lock);
267651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
267751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip = PreCallValidateQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
2678b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
26795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2680440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
268151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
268251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    VkResult result = dev_data->dispatch_table.QueueSubmit(queue, submitCount, pSubmits, fence);
268351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
268451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.lock();
268551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    PostCallRecordQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
268651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.unlock();
26875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
26885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
26895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2690f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic bool PreCallValidateAllocateMemory(layer_data *dev_data) {
2691f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = false;
2692f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (dev_data->memObjMap.size() >= dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount) {
2693f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
2694315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_16c004f8, "MEM",
2695f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        "Number of currently valid memory objects is not less than the maximum allowed (%u). %s",
2696f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount,
2697315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_16c004f8]);
2698f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    }
2699f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return skip;
2700f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
2701f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
2702f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic void PostCallRecordAllocateMemory(layer_data *dev_data, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory) {
2703f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    add_mem_obj_info(dev_data, dev_data->device, *pMemory, pAllocateInfo);
2704f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return;
2705f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
2706f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
270789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
270889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
2709f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
271056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
2711f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    std::unique_lock<std::mutex> lock(global_lock);
2712f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = PreCallValidateAllocateMemory(dev_data);
2713f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (!skip) {
2714f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.unlock();
2715f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        result = dev_data->dispatch_table.AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
2716f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.lock();
2717f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        if (VK_SUCCESS == result) {
2718f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz            PostCallRecordAllocateMemory(dev_data, pAllocateInfo, pMemory);
2719f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        }
2720e12739a56d02ca2fb5f0273862668e7475a21a6cMark Lobodzinski    }
27215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
27225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
27235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2724177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis// For given obj node, if it is use, flag a validation error and return callback result, else return false
2725177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisbool ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct,
2726177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                            UNIQUE_VALIDATION_ERROR_CODE error_code) {
2727cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.object_in_use) return false;
2728177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
2729177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (obj_node->in_use.load()) {
27307a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip |=
273102a510945ff39f3d9e486e456aca5bfa6ea0c43aMark Lobodzinski            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[obj_struct.type], obj_struct.handle,
27327a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                    __LINE__, error_code, "DS", "Cannot delete %s 0x%" PRIx64 " that is currently in use by a command buffer. %s",
27337a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                    object_string[obj_struct.type], obj_struct.handle, validation_error_map[error_code]);
2734177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
2735177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
2736177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
27375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2738177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic bool PreCallValidateFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO **mem_info, VK_OBJECT *obj_struct) {
27399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *mem_info = GetMemObjInfo(dev_data, mem);
27409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(mem), kVulkanObjectTypeDeviceMemory};
2741cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_memory) return false;
2742177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
2743177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (*mem_info) {
2744315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *mem_info, *obj_struct, VALIDATION_ERROR_2880054a);
2745177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
2746177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
2747177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
27485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2749177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic void PostCallRecordFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO *mem_info, VK_OBJECT obj_struct) {
2750177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Clear mem binding for any bound objects
275147705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis    for (auto obj : mem_info->obj_bindings) {
275202a510945ff39f3d9e486e456aca5bfa6ea0c43aMark Lobodzinski        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, get_debug_report_enum[obj.type], obj.handle, __LINE__,
27537a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                MEMTRACK_FREED_MEM_REF, "MEM", "VK Object 0x%" PRIxLEAST64 " still has a reference to mem obj 0x%" PRIxLEAST64,
27549b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                obj.handle, HandleToUint64(mem_info->mem));
275547705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        switch (obj.type) {
27567a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            case kVulkanObjectTypeImage: {
27579a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
2758cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(image_state);  // Any destroyed images should already be removed from bindings
2759cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                image_state->binding.mem = MEMORY_UNBOUND;
2760cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2761cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
27627a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            case kVulkanObjectTypeBuffer: {
27639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
2764cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(buffer_state);  // Any destroyed buffers should already be removed from bindings
2765cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                buffer_state->binding.mem = MEMORY_UNBOUND;
2766cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2767cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
2768cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
2769cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Should only have buffer or image objects bound to memory
2770cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(0);
2771177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        }
2772177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
2773177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Any bound cmd buffers are now invalid
277439c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, mem_info->cb_bindings, obj_struct);
2775177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    dev_data->memObjMap.erase(mem);
2776177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
2777177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis
2778177063aac84fac6f4e650c2629a08b48be643f96Tobin EhlisVKAPI_ATTR void VKAPI_CALL FreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
277956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
2780177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    DEVICE_MEM_INFO *mem_info = nullptr;
2781177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    VK_OBJECT obj_struct;
2782b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
2783177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = PreCallValidateFreeMemory(dev_data, mem, &mem_info, &obj_struct);
2784177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (!skip) {
2785177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.unlock();
2786177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        dev_data->dispatch_table.FreeMemory(device, mem, pAllocator);
2787177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.lock();
2788405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (mem != VK_NULL_HANDLE) {
2789405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordFreeMemory(dev_data, mem, mem_info, obj_struct);
2790405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
279174243a735fe102b370237ddf80d3e6f7ec5246dbMark Mueller    }
27925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
27935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2794f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis// Validate that given Map memory range is valid. This means that the memory should not already be mapped,
2795f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  and that the size of the map range should be:
2796f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  1. Not zero
2797f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  2. Within the size of the memory allocation
279851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateMapMemRange(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
27993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
28005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
28015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (size == 0) {
28023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
28039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
28043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "VkMapMemory: Attempting to map memory range of size zero");
28055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
280751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto mem_element = dev_data->memObjMap.find(mem);
280851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (mem_element != dev_data->memObjMap.end()) {
280957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        auto mem_info = mem_element->second.get();
28105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // It is an application error to call VkMapMemory on an object that is already mapped
2811de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (mem_info->mem_range.size != 0) {
28129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip =
28139b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
28149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
28159b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "VkMapMemory: Attempting to map memory on an already-mapped object 0x%" PRIxLEAST64, HandleToUint64(mem));
28165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
28175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
28185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate that offset + size is within object's allocationSize
28195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (size == VK_WHOLE_SIZE) {
2820de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if (offset >= mem_info->alloc_info.allocationSize) {
28213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
28229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                               HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
28233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64
28243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               " with size of VK_WHOLE_SIZE oversteps total array size 0x%" PRIx64,
28253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               offset, mem_info->alloc_info.allocationSize, mem_info->alloc_info.allocationSize);
28265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
28275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
2828de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if ((offset + size) > mem_info->alloc_info.allocationSize) {
28293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
2830315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               HandleToUint64(mem), __LINE__, VALIDATION_ERROR_31200552, "MEM",
28313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64 " oversteps total array size 0x%" PRIx64 ". %s",
28323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               offset, size + offset, mem_info->alloc_info.allocationSize,
2833315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               validation_error_map[VALIDATION_ERROR_31200552]);
28345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
28355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
28365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
28385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
28395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
284051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void storeMemRanges(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
28419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
284257fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
2843de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.offset = offset;
2844de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = size;
28455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
28475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
284851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool deleteMemRanges(layer_data *dev_data, VkDeviceMemory mem) {
28493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
28509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
285157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
2852de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (!mem_info->mem_range.size) {
28535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Valid Usage: memory must currently be mapped
28543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
2855315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           HandleToUint64(mem), __LINE__, VALIDATION_ERROR_33600562, "MEM",
28569b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           "Unmapping Memory without memory being mapped: mem obj 0x%" PRIxLEAST64 ". %s", HandleToUint64(mem),
2857315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           validation_error_map[VALIDATION_ERROR_33600562]);
28585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2859de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = 0;
28605f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info->shadow_copy) {
28615f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            free(mem_info->shadow_copy_base);
28625f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy_base = 0;
28635f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
28645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
28655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
28675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
28685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
28695f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski// Guard value for pad data
28705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char NoncoherentMemoryFillValue = 0xb;
28715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
28725f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinskistatic void initializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
28735f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                     void **ppData) {
28749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
287557fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
2876de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->p_driver_data = *ppData;
2877de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        uint32_t index = mem_info->alloc_info.memoryTypeIndex;
2878b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis        if (dev_data->phys_dev_mem_props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
28795f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
28805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
28815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (size == VK_WHOLE_SIZE) {
28825f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                size = mem_info->alloc_info.allocationSize - offset;
28835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
28845f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_pad_size = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
288516769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton            assert(SafeModulo(mem_info->shadow_pad_size,
28865f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment) == 0);
28875f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Ensure start of mapped region reflects hardware alignment constraints
28885f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t map_alignment = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
28895f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
28905f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // From spec: (ppData - offset) must be aligned to at least limits::minMemoryMapAlignment.
28915f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t start_offset = offset % map_alignment;
28925f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Data passed to driver will be wrapped by a guardband of data to detect over- or under-writes.
2893bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            mem_info->shadow_copy_base =
2894bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                malloc(static_cast<size_t>(2 * mem_info->shadow_pad_size + size + map_alignment + start_offset));
28955f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
28965f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy =
28975f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(mem_info->shadow_copy_base) + map_alignment) &
2898bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         ~(map_alignment - 1)) +
2899bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                start_offset;
290016769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton            assert(SafeModulo(reinterpret_cast<uintptr_t>(mem_info->shadow_copy) + mem_info->shadow_pad_size - start_offset,
29015f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  map_alignment) == 0);
29025f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
29036e17c244b21ce43ac57404a00a0d844039eed363Mark Lobodzinski            memset(mem_info->shadow_copy, NoncoherentMemoryFillValue, static_cast<size_t>(2 * mem_info->shadow_pad_size + size));
29045f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            *ppData = static_cast<char *>(mem_info->shadow_copy) + mem_info->shadow_pad_size;
29055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
29065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
29075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
29085f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
2909a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis// Verify that state for fence being waited on is appropriate. That is,
29109867daedbf52debc77d6568162ee21e071699b80Chris Forbes//  a fence being waited on should not already be signaled and
2911a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis//  it should have been submitted on a queue or during acquire next image
291249f6132af865afd5b7f413c91125971ac97c135aChris Forbesstatic inline bool verifyWaitFenceState(layer_data *dev_data, VkFence fence, const char *apiCall) {
29133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
29149b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes
29159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
29169b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes    if (pFence) {
2917cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_UNSIGNALED) {
29183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
29199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
29203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s called for fence 0x%" PRIxLEAST64
29213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " which has not been submitted on a Queue or during "
29223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "acquire next image.",
29239b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            apiCall, HandleToUint64(fence));
29245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
29255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
29263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
29275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2928a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
2929b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void RetireFence(layer_data *dev_data, VkFence fence) {
29309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
2931b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes    if (pFence->signaler.first != VK_NULL_HANDLE) {
293225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is a queue -- use this as proof that prior operations on that queue have completed.
29339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, pFence->signaler.first), pFence->signaler.second);
2934bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    } else {
293525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is the WSI. We're not tracking what the WSI op actually /was/ in CV yet, but we need to mark
293625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // the fence as retired.
2937d4513979120463171eb479cdded9336eb9944da1Chris Forbes        pFence->state = FENCE_RETIRED;
2938d4513979120463171eb479cdded9336eb9944da1Chris Forbes    }
2939b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes}
2940b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes
2941accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlisstatic bool PreCallValidateWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences) {
2942cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.wait_for_fences) return false;
2943accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = false;
2944accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    for (uint32_t i = 0; i < fence_count; i++) {
2945accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        skip |= verifyWaitFenceState(dev_data, fences[i], "vkWaitForFences");
2946b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        skip |= VerifyQueueStateToFence(dev_data, fences[i]);
2947accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
2948accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    return skip;
2949accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
2950accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
2951b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences, VkBool32 wait_all) {
2952b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    // When we know that all fences are complete we can clean/remove their CBs
2953accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    if ((VK_TRUE == wait_all) || (1 == fence_count)) {
2954accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        for (uint32_t i = 0; i < fence_count; i++) {
2955b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            RetireFence(dev_data, fences[i]);
2956accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        }
2957accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
2958accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    // NOTE : Alternate case not handled here is when some fences have completed. In
2959accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    //  this case for app to guarantee which fences completed it will have to call
2960b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    //  vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
2961accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
2962accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
2963bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
2964bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint64_t timeout) {
296556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
29665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Verify fence status of submitted fences
2967b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
2968accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = PreCallValidateWaitForFences(dev_data, fenceCount, pFences);
2969b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
2970cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
2971a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
29724a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.WaitForFences(device, fenceCount, pFences, waitAll, timeout);
2973414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller
29745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
2975b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
2976b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordWaitForFences(dev_data, fenceCount, pFences, waitAll);
2977b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
29785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
29795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
29805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
29815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2982f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlisstatic bool PreCallValidateGetFenceStatus(layer_data *dev_data, VkFence fence) {
2983cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_fence_state) return false;
2984f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    return verifyWaitFenceState(dev_data, fence, "vkGetFenceStatus");
2985f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis}
2986f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
2987b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordGetFenceStatus(layer_data *dev_data, VkFence fence) { RetireFence(dev_data, fence); }
2988f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
298989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL GetFenceStatus(VkDevice device, VkFence fence) {
299056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
2991b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
2992f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    bool skip = PreCallValidateGetFenceStatus(dev_data, fence);
2993b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
2994cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
2995a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
29964a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetFenceStatus(device, fence);
29975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
2998f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.lock();
2999b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordGetFenceStatus(dev_data, fence);
3000f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.unlock();
30015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
30025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
30035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30053b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlisstatic void PostCallRecordGetDeviceQueue(layer_data *dev_data, uint32_t q_family_index, VkQueue queue) {
30063b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    // Add queue to tracking set only if it is new
30073b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    auto result = dev_data->queues.emplace(queue);
30083b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    if (result.second == true) {
300936c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        QUEUE_STATE *queue_state = &dev_data->queueMap[queue];
30103b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queue = queue;
30113b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queueFamilyIndex = q_family_index;
30123b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->seq = 0;
30133b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    }
30143b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis}
30153b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis
3016bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
301756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
30184a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
3019b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
3020b376edacad6f7ab3fcc0a914e9b1673a9fcd5143Mark Lobodzinski
30213b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    PostCallRecordGetDeviceQueue(dev_data, queueFamilyIndex, *pQueue);
30225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
302436c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool PreCallValidateQueueWaitIdle(layer_data *dev_data, VkQueue queue, QUEUE_STATE **queue_state) {
30259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *queue_state = GetQueueState(dev_data, queue);
3026cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.queue_wait_idle) return false;
3027e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    return VerifyQueueStateToSeq(dev_data, *queue_state, (*queue_state)->seq + (*queue_state)->submissions.size());
30284273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
30294273a1c157585a645dca4c960086032793899d05Tobin Ehlis
303036c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void PostCallRecordQueueWaitIdle(layer_data *dev_data, QUEUE_STATE *queue_state) {
3031e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    RetireWorkOnQueue(dev_data, queue_state, queue_state->seq + queue_state->submissions.size());
30324273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
30334273a1c157585a645dca4c960086032793899d05Tobin Ehlis
303489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueueWaitIdle(VkQueue queue) {
303556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
303636c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    QUEUE_STATE *queue_state = nullptr;
30379867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
30384273a1c157585a645dca4c960086032793899d05Tobin Ehlis    bool skip = PreCallValidateQueueWaitIdle(dev_data, queue, &queue_state);
30399867daedbf52debc77d6568162ee21e071699b80Chris Forbes    lock.unlock();
3040cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
30414a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueueWaitIdle(queue);
30424273a1c157585a645dca4c960086032793899d05Tobin Ehlis    if (VK_SUCCESS == result) {
3043e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.lock();
3044e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        PostCallRecordQueueWaitIdle(dev_data, queue_state);
3045e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.unlock();
30464273a1c157585a645dca4c960086032793899d05Tobin Ehlis    }
30475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
30485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30508767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic bool PreCallValidateDeviceWaitIdle(layer_data *dev_data) {
3051cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.device_wait_idle) return false;
30528767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = false;
30538767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
30548767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
30558767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
30568767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    return skip;
30578767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
30588767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
30598767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic void PostCallRecordDeviceWaitIdle(layer_data *dev_data) {
30608767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
30618767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        RetireWorkOnQueue(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
30628767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
30638767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
30648767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
306589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL DeviceWaitIdle(VkDevice device) {
306656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
3067b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
30688767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = PreCallValidateDeviceWaitIdle(dev_data);
3069b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
3070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
30714a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.DeviceWaitIdle(device);
30728767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    if (VK_SUCCESS == result) {
30738767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.lock();
30748767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        PostCallRecordDeviceWaitIdle(dev_data);
30758767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.unlock();
30768767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
30775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
30785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30801d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic bool PreCallValidateDestroyFence(layer_data *dev_data, VkFence fence, FENCE_NODE **fence_node, VK_OBJECT *obj_struct) {
30819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *fence_node = GetFenceNode(dev_data, fence);
30829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(fence), kVulkanObjectTypeFence};
3083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_fence) return false;
30841d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = false;
30851d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (*fence_node) {
30861d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        if ((*fence_node)->state == FENCE_INFLIGHT) {
30871d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
3088315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(fence), __LINE__, VALIDATION_ERROR_24e008c0, "DS", "Fence 0x%" PRIx64 " is in use. %s",
3089315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(fence), validation_error_map[VALIDATION_ERROR_24e008c0]);
30901d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        }
30911d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
30921d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    return skip;
30931d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis}
30941d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
30951d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic void PostCallRecordDestroyFence(layer_data *dev_data, VkFence fence) { dev_data->fenceMap.erase(fence); }
30961d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
309789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
309856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
30991d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    // Common data objects used pre & post call
31001d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    FENCE_NODE *fence_node = nullptr;
31011d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    VK_OBJECT obj_struct;
3102b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
31031d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = PreCallValidateDestroyFence(dev_data, fence, &fence_node, &obj_struct);
31041344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
31051d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (!skip) {
31061d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.unlock();
31074a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyFence(device, fence, pAllocator);
31081d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.lock();
31091d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        PostCallRecordDestroyFence(dev_data, fence);
31101d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
31115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
31125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3113c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic bool PreCallValidateDestroySemaphore(layer_data *dev_data, VkSemaphore semaphore, SEMAPHORE_NODE **sema_node,
3114c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis                                            VK_OBJECT *obj_struct) {
31159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sema_node = GetSemaphoreNode(dev_data, semaphore);
31169b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(semaphore), kVulkanObjectTypeSemaphore};
3117cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_semaphore) return false;
3118c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = false;
3119c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    if (*sema_node) {
3120315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sema_node, *obj_struct, VALIDATION_ERROR_268008e2);
3121c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    }
3122c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    return skip;
3123c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis}
3124c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
3125c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic void PostCallRecordDestroySemaphore(layer_data *dev_data, VkSemaphore sema) { dev_data->semaphoreMap.erase(sema); }
3126c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
3127bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
312856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
3129c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    SEMAPHORE_NODE *sema_node;
3130c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    VK_OBJECT obj_struct;
3131e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
3132c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = PreCallValidateDestroySemaphore(dev_data, semaphore, &sema_node, &obj_struct);
3133eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis    if (!skip) {
3134eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        lock.unlock();
31354a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySemaphore(device, semaphore, pAllocator);
3136c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        lock.lock();
3137c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        PostCallRecordDestroySemaphore(dev_data, semaphore);
313899d938c90c2f000ee73fb13513dacf84ffa5651fMark Mueller    }
31395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
31405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
31414710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic bool PreCallValidateDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE **event_state, VK_OBJECT *obj_struct) {
31429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *event_state = GetEventNode(dev_data, event);
31439b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(event), kVulkanObjectTypeEvent};
3144cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_event) return false;
3145d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = false;
3146d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    if (*event_state) {
3147315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *event_state, *obj_struct, VALIDATION_ERROR_24c008f2);
3148d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    }
3149d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    return skip;
3150d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
3151d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
31524710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic void PostCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
315339c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, event_state->cb_bindings, obj_struct);
3154d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    dev_data->eventMap.erase(event);
3155d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
3156d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
315789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
315856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
31594710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    EVENT_STATE *event_state = nullptr;
3160d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    VK_OBJECT obj_struct;
3161b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
3162d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = PreCallValidateDestroyEvent(dev_data, event, &event_state, &obj_struct);
3163f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
3164f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
31654a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyEvent(device, event, pAllocator);
3166d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        lock.lock();
3167405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (event != VK_NULL_HANDLE) {
3168405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyEvent(dev_data, event, event_state, obj_struct);
3169405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
3170f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
31715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
31725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
317383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlisstatic bool PreCallValidateDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE **qp_state,
317483c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis                                            VK_OBJECT *obj_struct) {
31759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *qp_state = GetQueryPoolNode(dev_data, query_pool);
31769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(query_pool), kVulkanObjectTypeQueryPool};
3177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_query_pool) return false;
317883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = false;
317983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    if (*qp_state) {
3180315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *qp_state, *obj_struct, VALIDATION_ERROR_26200632);
318183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    }
318283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    return skip;
318383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
318483c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
3185bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void PostCallRecordDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE *qp_state,
3186bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VK_OBJECT obj_struct) {
318783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    invalidateCommandBuffers(dev_data, qp_state->cb_bindings, obj_struct);
318883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    dev_data->queryPoolMap.erase(query_pool);
318983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
319083c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
3191bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
319256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
319383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    QUERY_POOL_NODE *qp_state = nullptr;
319483c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    VK_OBJECT obj_struct;
3195ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
319683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = PreCallValidateDestroyQueryPool(dev_data, queryPool, &qp_state, &obj_struct);
3197f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
3198f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
31994a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyQueryPool(device, queryPool, pAllocator);
320083c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        lock.lock();
3201405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (queryPool != VK_NULL_HANDLE) {
3202405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyQueryPool(dev_data, queryPool, qp_state, obj_struct);
3203405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
3204f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
32055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32069fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic bool PreCallValidateGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
32079fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               uint32_t query_count, VkQueryResultFlags flags,
32089fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
3209a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    // TODO: clean this up, it's insanely wasteful.
3210a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    for (auto cmd_buffer : dev_data->commandBufferMap) {
3211a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        if (cmd_buffer.second->in_use.load()) {
3212a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            for (auto query_state_pair : cmd_buffer.second->queryToStateMap) {
3213a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                (*queries_in_flight)[query_state_pair.first].push_back(
3214a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                    cmd_buffer.first);
3215a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            }
32165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
32175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3218cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_query_pool_results) return false;
32199fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = false;
32209fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
32219fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
32229fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
32239fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
32249fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
3225ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski            // Available and in flight
32269fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
32279fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
32289fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
32299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
32309fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
32319fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair == cb->waitedEventsBeforeQueryReset.end()) {
32329fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
32339fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
32349fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is in flight.",
32359b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(query_pool), first_query + i);
3236ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                    }
3237ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
3238ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable and in flight
32399fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
32409fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                       !query_state_pair->second) {
3241ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // TODO : Can there be the same query in use by multiple command buffers in flight?
3242ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                bool make_available = false;
32439fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
32449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
32459fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    make_available |= cb->queryToStateMap[query];
3246ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
3247ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) {
32489fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
32499fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
32509fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
32519b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(query_pool), first_query + i);
32525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
3253ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable
32549fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair != dev_data->queryToStateMap.end() && !query_state_pair->second) {
32559fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
32569fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
32579fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
32589b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(query_pool), first_query + i);
32599fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                // Uninitialized
32609fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair == dev_data->queryToStateMap.end()) {
32619fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
32629fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
32639fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64
32649fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                " with index %d as data has not been collected for this index.",
32659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(query_pool), first_query + i);
32665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
32675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
32685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
32699fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return skip;
32709fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
32719fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
32729fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic void PostCallRecordGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
32739fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              uint32_t query_count,
32749fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
32759fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
32769fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
32779fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
32789fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
32799fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
32809fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            // Available and in flight
32819fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
32829fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
32839fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
32849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
32859fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
32869fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair != cb->waitedEventsBeforeQueryReset.end()) {
32879fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        for (auto event : query_event_pair->second) {
32889fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                            dev_data->eventMap[event].needsSignaled = true;
32899fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        }
32909fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    }
32919fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                }
32929fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            }
32939fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        }
32949fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    }
32959fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
32969fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
32979fdee42cd357379efb9aa27f90beb75d1f824955Tobin EhlisVKAPI_ATTR VkResult VKAPI_CALL GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
32989fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                                   size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags) {
329956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
33009fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    unordered_map<QueryObject, vector<VkCommandBuffer>> queries_in_flight;
33019fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
33029fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = PreCallValidateGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, flags, &queries_in_flight);
3303b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
3304cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
33059fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    VkResult result =
33069fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        dev_data->dispatch_table.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
33079fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.lock();
33089fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    PostCallRecordGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, &queries_in_flight);
33099fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.unlock();
33109fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return result;
33115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3313825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if given ranges intersect, else false
3314825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Prereq : For both ranges, range->end - range->start > 0. This case should have already resulted
3315825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  in an error so not checking that here
3316825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// pad_ranges bool indicates a linear and non-linear comparison which requires padding
33173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski// In the case where padding is required, if an alias is encountered then a validation error is reported and skip
33183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski//  may be set by the callback function so caller should merge in skip value if padding case is possible.
33192ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton// This check can be skipped by passing skip_checks=true, for call sites outside the validation path.
33203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinskistatic bool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, MEMORY_RANGE const *range2, bool *skip,
33212ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton                            bool skip_checks) {
33223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    *skip = false;
3323825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_start = range1->start;
3324825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_end = range1->end;
3325825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_start = range2->start;
3326825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_end = range2->end;
3327825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    VkDeviceSize pad_align = 1;
3328825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (range1->linear != range2->linear) {
3329825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        pad_align = dev_data->phys_dev_properties.properties.limits.bufferImageGranularity;
3330825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
3331cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_end & ~(pad_align - 1)) < (r2_start & ~(pad_align - 1))) return false;
3332cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_start & ~(pad_align - 1)) > (r2_end & ~(pad_align - 1))) return false;
333347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
33342ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton    if (!skip_checks && (range1->linear != range2->linear)) {
333553ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        // In linear vs. non-linear case, warn of aliasing
3336825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_linear_str = range1->linear ? "Linear" : "Non-linear";
3337825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_type_str = range1->image ? "image" : "buffer";
3338825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_linear_str = range2->linear ? "linear" : "non-linear";
3339825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_type_str = range2->image ? "image" : "buffer";
3340825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto obj_type = range1->image ? VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT : VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;
33413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        *skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, obj_type, range1->handle, 0,
33423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                         MEMTRACK_INVALID_ALIASING, "MEM", "%s %s 0x%" PRIx64 " is aliased with %s %s 0x%" PRIx64
33433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           " which may indicate a bug. For further info refer to the "
33443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "Buffer-Image Granularity section of the Vulkan specification. "
33453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "(https://www.khronos.org/registry/vulkan/specs/1.0-extensions/"
33463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "xhtml/vkspec.html#resources-bufferimagegranularity)",
33473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                         r1_linear_str, r1_type_str, range1->handle, r2_linear_str, r2_type_str, range2->handle);
334847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
3349825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Ranges intersect
3350825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    return true;
335147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
3352623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis// Simplified rangesIntersect that calls above function to check range1 for intersection with offset & end addresses
3353c3340a06ecac4d7b9540592cae339f8fc224d0b1Mark Lobodzinskibool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, VkDeviceSize offset, VkDeviceSize end) {
3354825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Create a local MEMORY_RANGE struct to wrap offset/size
3355825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    MEMORY_RANGE range_wrap;
3356825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Synch linear with range1 to avoid padding and potential validation error case
3357825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.linear = range1->linear;
3358825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.start = offset;
3359cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    range_wrap.end = end;
3360825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    bool tmp_bool;
33612ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton    return rangesIntersect(dev_data, range1, &range_wrap, &tmp_bool, true);
3362825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
3363cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given mem_info, set all ranges valid that intersect [offset-end] range
3364cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// TODO : For ranges where there is no alias, we may want to create new buffer ranges that are valid
3365cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlisstatic void SetMemRangesValid(layer_data const *dev_data, DEVICE_MEM_INFO *mem_info, VkDeviceSize offset, VkDeviceSize end) {
3366cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    bool tmp_bool = false;
3367f6e16b28b808a342cb92768001afa2cfeee08a11Tobin Ehlis    MEMORY_RANGE map_range = {};
3368cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.linear = true;
3369cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.start = offset;
3370cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.end = end;
3371cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    for (auto &handle_range_pair : mem_info->bound_ranges) {
33722ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &handle_range_pair.second, &map_range, &tmp_bool, false)) {
3373cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : WARN here if tmp_bool true?
3374cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            handle_range_pair.second.valid = true;
3375cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        }
3376cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    }
3377cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis}
33780ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
33790ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info,
33800ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                      VkDeviceSize memoryOffset, VkMemoryRequirements memRequirements, bool is_image,
33810ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                      bool is_linear, const char *api_name) {
33820ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    bool skip = false;
33830ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
33840ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    MEMORY_RANGE range;
33850ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.image = is_image;
33860ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.handle = handle;
33870ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.linear = is_linear;
33880ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.valid = mem_info->global_valid;
33890ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.memory = mem_info->mem;
33900ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.start = memoryOffset;
33910ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.size = memRequirements.size;
33920ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.end = memoryOffset + memRequirements.size - 1;
33930ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.aliases.clear();
33940ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
33950ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    // Check for aliasing problems.
33960ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    for (auto &obj_range_pair : mem_info->bound_ranges) {
33970ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto check_range = &obj_range_pair.second;
33980ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        bool intersection_error = false;
33992ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &range, check_range, &intersection_error, false)) {
34000ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= intersection_error;
34010ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            range.aliases.insert(check_range);
34020ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
34030ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    }
34040ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
34050ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    if (memoryOffset >= mem_info->alloc_info.allocationSize) {
3406315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        UNIQUE_VALIDATION_ERROR_CODE error_code = is_image ? VALIDATION_ERROR_1740082c : VALIDATION_ERROR_1700080e;
34070ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
34089b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(mem_info->mem), __LINE__, error_code, "MEM",
34090ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
34100ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       "), memoryOffset=0x%" PRIxLEAST64 " must be less than the memory allocation size 0x%" PRIxLEAST64 ". %s",
34119b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       api_name, HandleToUint64(mem_info->mem), handle, memoryOffset, mem_info->alloc_info.allocationSize,
34129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       validation_error_map[error_code]);
34130ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    }
34140ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
34150ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    return skip;
34160ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
34170ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
3418825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Object with given handle is being bound to memory w/ given mem_info struct.
3419825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Track the newly bound memory range with given memoryOffset
3420825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Also scan any previous ranges, track aliased ranges with new range, and flag an error if a linear
3421825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  and non-linear range incorrectly overlap.
3422825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if an error is flagged and the user callback returns "true", otherwise false
3423825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_image indicates an image object, otherwise handle is for a buffer
3424825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_linear indicates a buffer or linear image
34250ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info, VkDeviceSize memoryOffset,
34260ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                              VkMemoryRequirements memRequirements, bool is_image, bool is_linear) {
34275360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    MEMORY_RANGE range;
3428825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
3429825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.image = is_image;
343047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.handle = handle;
3431825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.linear = is_linear;
3432f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis    range.valid = mem_info->global_valid;
3433825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.memory = mem_info->mem;
343447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.start = memoryOffset;
3435825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.size = memRequirements.size;
343647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.end = memoryOffset + memRequirements.size - 1;
34375360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    range.aliases.clear();
34385360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // Update Memory aliasing
343975f4c8cec0996021a4258b9bf920a9e0fea4eac1Tobin 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
34405360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // inserted into map before loop to get the final ptr, then we may enter loop when not needed & we check range against itself
34415360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    std::unordered_set<MEMORY_RANGE *> tmp_alias_ranges;
3442825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto &obj_range_pair : mem_info->bound_ranges) {
3443825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto check_range = &obj_range_pair.second;
34445360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        bool intersection_error = false;
34452ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &range, check_range, &intersection_error, true)) {
3446825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis            range.aliases.insert(check_range);
34475360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis            tmp_alias_ranges.insert(check_range);
3448825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        }
3449825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
34505360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    mem_info->bound_ranges[handle] = std::move(range);
34515360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    for (auto tmp_range : tmp_alias_ranges) {
34525360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        tmp_range->aliases.insert(&mem_info->bound_ranges[handle]);
34535360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    }
3454825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (is_image)
3455825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.insert(handle);
3456825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    else
3457825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.insert(handle);
345847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
345947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
34600ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info,
34610ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                           VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, bool is_linear,
34620ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                           const char *api_name) {
34639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    return ValidateInsertMemoryRange(dev_data, HandleToUint64(image), mem_info, mem_offset, mem_reqs, true, is_linear, api_name);
34640ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
34650ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
34660ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                   VkMemoryRequirements mem_reqs, bool is_linear) {
34679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    InsertMemoryRange(dev_data, HandleToUint64(image), mem_info, mem_offset, mem_reqs, true, is_linear);
3468825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
3469825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
34700ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info,
34710ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                            VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, const char *api_name) {
34729b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    return ValidateInsertMemoryRange(dev_data, HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, false, true, api_name);
34730ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
34740ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
34750ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                    VkMemoryRequirements mem_reqs) {
34769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    InsertMemoryRange(dev_data, HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, false, true);
3477825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
3478825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
3479825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Remove MEMORY_RANGE struct for give handle from bound_ranges of mem_info
3480825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  is_image indicates if handle is for image or buffer
3481825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  This function will also remove the handle-to-index mapping from the appropriate
3482825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  map and clean up any aliases for range being removed.
3483825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic void RemoveMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info, bool is_image) {
3484825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto erase_range = &mem_info->bound_ranges[handle];
3485825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto alias_range : erase_range->aliases) {
3486825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        alias_range->aliases.erase(erase_range);
348747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
34885360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    erase_range->aliases.clear();
3489825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    mem_info->bound_ranges.erase(handle);
34901cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    if (is_image) {
3491825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.erase(handle);
34921cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    } else {
3493825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.erase(handle);
34941cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    }
349547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
349647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
3497842b2d28ded1c6e2c38491a81213d0e1d1b7295aMark Lobodzinskivoid RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, false); }
3498825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
34998c59133586421be878d393799b30044497f77727Mark Lobodzinskivoid RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, true); }
3500825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
3501bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
350256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
3503e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
3504e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    VK_OBJECT obj_struct;
3505b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
3506e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    bool skip = PreCallValidateDestroyBuffer(dev_data, buffer, &buffer_state, &obj_struct);
3507e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    if (!skip) {
3508b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
35094a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBuffer(device, buffer, pAllocator);
3510e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        lock.lock();
3511405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (buffer != VK_NULL_HANDLE) {
3512405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBuffer(dev_data, buffer, buffer_state, obj_struct);
3513405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
351447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
35155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3517bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
351856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
3519f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
35208e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    BUFFER_VIEW_STATE *buffer_view_state = nullptr;
35218e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    VK_OBJECT obj_struct;
3522a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
35238e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    // Validate state before calling down chain, update common data if we'll be calling down chain
35248e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    bool skip = PreCallValidateDestroyBufferView(dev_data, bufferView, &buffer_view_state, &obj_struct);
352538e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis    if (!skip) {
352638e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis        lock.unlock();
35274a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBufferView(device, bufferView, pAllocator);
35288e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis        lock.lock();
3529405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (bufferView != VK_NULL_HANDLE) {
3530405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBufferView(dev_data, bufferView, buffer_view_state, obj_struct);
3531405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
35325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
35335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35352a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
353656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
35371facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    IMAGE_STATE *image_state = nullptr;
35382a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    VK_OBJECT obj_struct;
35392a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
35402a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    bool skip = PreCallValidateDestroyImage(dev_data, image, &image_state, &obj_struct);
35412a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    if (!skip) {
3542f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        lock.unlock();
35434a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImage(device, image, pAllocator);
35442a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        lock.lock();
3545405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (image != VK_NULL_HANDLE) {
3546405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImage(dev_data, image, image_state, obj_struct);
3547405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
35485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
35495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35514261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinskistatic bool ValidateMemoryTypes(const layer_data *dev_data, const DEVICE_MEM_INFO *mem_info, const uint32_t memory_type_bits,
3552f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                const char *funcName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
35533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3554de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis    if (((1 << mem_info->alloc_info.memoryTypeIndex) & memory_type_bits) == 0) {
35553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
35569b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(mem_info->mem), __LINE__, msgCode, "MT",
35573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "%s(): MemoryRequirements->memoryTypeBits (0x%X) for this object type are not compatible with the memory "
35583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "type (0x%X) of this memory object 0x%" PRIx64 ". %s",
35599b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       funcName, memory_type_bits, mem_info->alloc_info.memoryTypeIndex, HandleToUint64(mem_info->mem),
35609b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       validation_error_map[msgCode]);
35614261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    }
35623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
35634261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski}
35644261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski
3565160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic bool PreCallValidateBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
3566160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                            VkDeviceSize memoryOffset) {
35679207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    bool skip = false;
35685cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
3569160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
35709207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // Track objects tied to memory
35719b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t buffer_handle = HandleToUint64(buffer);
35727a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip = ValidateSetMemBinding(dev_data, mem, buffer_handle, kVulkanObjectTypeBuffer, "vkBindBufferMemory()");
35732eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (!buffer_state->memory_requirements_checked) {
35742eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // There's not an explicit requirement in the spec to call vkGetBufferMemoryRequirements() prior to calling
35759207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // BindBufferMemory, but it's implied in that memory being bound must conform with VkMemoryRequirements from
35769207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // vkGetBufferMemoryRequirements()
35779207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
35789207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle, __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
35799207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): Binding memory to buffer 0x%" PRIxLEAST64
35809207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but vkGetBufferMemoryRequirements() has not been called on that buffer.",
35819207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle);
35822eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // Make the call for them so we can verify the state
35832eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.unlock();
35849207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            dev_data->dispatch_table.GetBufferMemoryRequirements(dev_data->device, buffer, &buffer_state->requirements);
35852eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.lock();
35862eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        }
358747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
35880ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Validate bound memory range information
35899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
359057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
35910ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= ValidateInsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements,
35920ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                                    "vkBindBufferMemory()");
35939207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, buffer_state->requirements.memoryTypeBits, "vkBindBufferMemory()",
3594315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        VALIDATION_ERROR_17000816);
359547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
359647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
35972c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate memory requirements alignment
359816769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(memoryOffset, buffer_state->requirements.alignment) != 0) {
3599f60e41965223825191505eebc96491bb52e494a2Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
3600315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            buffer_handle, __LINE__, VALIDATION_ERROR_17000818, "DS",
36019207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64
36029207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but must be an integer multiple of the "
36039207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
36049207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
3605315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            memoryOffset, buffer_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_17000818]);
36062c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
3607ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
3608160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements size
3609160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        if (buffer_state->requirements.size > (mem_info->alloc_info.allocationSize - memoryOffset)) {
3610160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
3611315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            buffer_handle, __LINE__, VALIDATION_ERROR_1700081a, "DS",
3612160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindBufferMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
3613160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be at least as large as "
3614160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
3615160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
3616160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            mem_info->alloc_info.allocationSize - memoryOffset, buffer_state->requirements.size,
3617315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1700081a]);
3618160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
3619160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
36202c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate device limits alignments
3621ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        static const VkBufferUsageFlagBits usage_list[3] = {
3622ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
3623bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT};
3624bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *memory_type[3] = {"texel", "uniform", "storage"};
3625bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *offset_name[3] = {"minTexelBufferOffsetAlignment", "minUniformBufferOffsetAlignment",
3626bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             "minStorageBufferOffsetAlignment"};
3627cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
36289207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // TODO:  vk_validation_stats.py cannot abide braces immediately preceding or following a validation error enum
3629cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format off
3630315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        static const UNIQUE_VALIDATION_ERROR_CODE msgCode[3] = { VALIDATION_ERROR_17000810, VALIDATION_ERROR_17000812,
3631315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            VALIDATION_ERROR_17000814 };
3632cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format on
3633ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
3634ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        // Keep this one fresh!
3635ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        const VkDeviceSize offset_requirement[3] = {
3636ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment,
3637ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
3638bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment};
36398718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        VkBufferUsageFlags usage = dev_data->bufferMap[buffer].get()->createInfo.usage;
3640ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
3641ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        for (int i = 0; i < 3; i++) {
3642ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            if (usage & usage_list[i]) {
364316769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                if (SafeModulo(memoryOffset, offset_requirement[i]) != 0) {
36449207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                    skip |= log_msg(
3645f60e41965223825191505eebc96491bb52e494a2Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, buffer_handle,
3646cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, msgCode[i], "DS", "vkBindBufferMemory(): %s memoryOffset is 0x%" PRIxLEAST64
3647cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    " but must be a multiple of "
3648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    "device limit %s 0x%" PRIxLEAST64 ". %s",
3649cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        memory_type[i], memoryOffset, offset_name[i], offset_requirement[i], validation_error_map[msgCode[i]]);
3650ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                }
36512c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves            }
36522c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
36535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36549207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    return skip;
36559207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
36569207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
3657160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic void PostCallRecordBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
3658160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                           VkDeviceSize memoryOffset) {
36599207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (buffer_state) {
3660160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
36610ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Track bound memory range information
36620ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto mem_info = GetMemObjInfo(dev_data, mem);
36630ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        if (mem_info) {
36640ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            InsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements);
36650ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
36660ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
3667c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
36689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t buffer_handle = HandleToUint64(buffer);
36697a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        SetMemBinding(dev_data, mem, buffer_handle, kVulkanObjectTypeBuffer, "vkBindBufferMemory()");
3670c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
36719207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.mem = mem;
36729207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.offset = memoryOffset;
36739207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.size = buffer_state->requirements.size;
36749207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    }
36759207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
36769207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
36779207132ef623d47fcbdfeb9ebc796eade35a2f4cCort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
36789207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
36799207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3680160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    auto buffer_state = GetBufferState(dev_data, buffer);
3681160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    bool skip = PreCallValidateBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
36829207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (!skip) {
36834a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.BindBufferMemory(device, buffer, mem, memoryOffset);
36849207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        if (result == VK_SUCCESS) {
3685160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            PostCallRecordBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
36869207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        }
36875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
36895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3691bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
3692bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       VkMemoryRequirements *pMemoryRequirements) {
369356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
369415caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
36959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
369615caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (buffer_state) {
369715caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        buffer_state->requirements = *pMemoryRequirements;
36982eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        buffer_state->memory_requirements_checked = true;
369915caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
37005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3702bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
370356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
370415caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetImageMemoryRequirements(device, image, pMemoryRequirements);
37059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, image);
370615caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (image_state) {
370715caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        image_state->requirements = *pMemoryRequirements;
37082eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        image_state->memory_requirements_checked = true;
370915caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
37105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
3711593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
3712bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
371356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
3714f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
3715f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    IMAGE_VIEW_STATE *image_view_state = nullptr;
3716f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    VK_OBJECT obj_struct;
3717a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
3718f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    bool skip = PreCallValidateDestroyImageView(dev_data, imageView, &image_view_state, &obj_struct);
3719d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    if (!skip) {
3720d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis        lock.unlock();
37214a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImageView(device, imageView, pAllocator);
3722f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis        lock.lock();
3723405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (imageView != VK_NULL_HANDLE) {
3724405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImageView(dev_data, imageView, image_view_state, obj_struct);
3725405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
3726d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    }
37275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3729bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyShaderModule(VkDevice device, VkShaderModule shaderModule,
3730bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               const VkAllocationCallbacks *pAllocator) {
373156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
3732918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
3733b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
373451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->shaderModuleMap.erase(shaderModule);
3735b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
3736918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
373751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->dispatch_table.DestroyShaderModule(device, shaderModule, pAllocator);
37385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37404c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool PreCallValidateDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE **pipeline_state,
37418bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                           VK_OBJECT *obj_struct) {
374294165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *pipeline_state = getPipelineState(dev_data, pipeline);
37439b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(pipeline), kVulkanObjectTypePipeline};
3744cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_pipeline) return false;
37458bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = false;
37468bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    if (*pipeline_state) {
3747315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *pipeline_state, *obj_struct, VALIDATION_ERROR_25c005fa);
37488bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    }
37498bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    return skip;
37508bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
37518bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
37524c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void PostCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
37538bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                          VK_OBJECT obj_struct) {
37548bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    // Any bound cmd buffers are now invalid
375539c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, pipeline_state->cb_bindings, obj_struct);
37560a136bc9fe42c042857c90a421d0426bd0c029efGabríel Arthúr Pétursson    delete getPipelineState(dev_data, pipeline);
37578bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    dev_data->pipelineMap.erase(pipeline);
37588bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
37598bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
3760bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
376156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
37624c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pipeline_state = nullptr;
37638bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    VK_OBJECT obj_struct;
3764e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
37658bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = PreCallValidateDestroyPipeline(dev_data, pipeline, &pipeline_state, &obj_struct);
3766f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
3767f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
37684a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyPipeline(device, pipeline, pAllocator);
37698bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis        lock.lock();
3770405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (pipeline != VK_NULL_HANDLE) {
3771405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyPipeline(dev_data, pipeline, pipeline_state, obj_struct);
3772405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
3773f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
37745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3776bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout,
3777bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
377856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
3779e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
37806792ea7cc0ce5fa64b7bd6c946460608cbda91c7Tobin Ehlis    dev_data->pipelineLayoutMap.erase(pipelineLayout);
3781e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    lock.unlock();
3782e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
37834a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineLayout(device, pipelineLayout, pAllocator);
37845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3786d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic bool PreCallValidateDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE **sampler_state,
3787806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                          VK_OBJECT *obj_struct) {
37889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sampler_state = GetSamplerState(dev_data, sampler);
37899b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(sampler), kVulkanObjectTypeSampler};
3790cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_sampler) return false;
3791806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = false;
3792806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    if (*sampler_state) {
3793315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sampler_state, *obj_struct, VALIDATION_ERROR_26600874);
3794806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    }
3795806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    return skip;
3796806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
3797806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
3798d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic void PostCallRecordDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE *sampler_state,
3799806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                         VK_OBJECT obj_struct) {
3800806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    // Any bound cmd buffers are now invalid
3801cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (sampler_state) invalidateCommandBuffers(dev_data, sampler_state->cb_bindings, obj_struct);
3802806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    dev_data->samplerMap.erase(sampler);
3803806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
3804806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
3805bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
380656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
3807d31a44af6da568692a73201825459689c9431867Tobin Ehlis    SAMPLER_STATE *sampler_state = nullptr;
3808806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    VK_OBJECT obj_struct;
380956f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
3810806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = PreCallValidateDestroySampler(dev_data, sampler, &sampler_state, &obj_struct);
3811f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
3812f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
38134a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySampler(device, sampler, pAllocator);
3814806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        lock.lock();
3815405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (sampler != VK_NULL_HANDLE) {
3816405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroySampler(dev_data, sampler, sampler_state, obj_struct);
3817405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
3818f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
38195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
382179c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlisstatic void PostCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDescriptorSetLayout ds_layout) {
382279c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->descriptorSetLayoutMap.erase(ds_layout);
382379c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis}
382479c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis
3825bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
3826bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator) {
382756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
382879c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->dispatch_table.DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
382979c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
383079c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    PostCallRecordDestroyDescriptorSetLayout(dev_data, descriptorSetLayout);
38315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3833c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic bool PreCallValidateDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool pool,
3834a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                 DESCRIPTOR_POOL_STATE **desc_pool_state, VK_OBJECT *obj_struct) {
38359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *desc_pool_state = GetDescriptorPoolState(dev_data, pool);
38369b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(pool), kVulkanObjectTypeDescriptorPool};
3837cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_descriptor_pool) return false;
3838c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = false;
3839c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (*desc_pool_state) {
3840315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *desc_pool_state, *obj_struct, VALIDATION_ERROR_2440025e);
3841c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
3842c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    return skip;
3843c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
3844c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
3845c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic void PostCallRecordDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool descriptorPool,
3846a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                DESCRIPTOR_POOL_STATE *desc_pool_state, VK_OBJECT obj_struct) {
3847c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Any bound cmd buffers are now invalid
384839c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, desc_pool_state->cb_bindings, obj_struct);
3849c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Free sets that were in this pool
3850c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    for (auto ds : desc_pool_state->sets) {
3851c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        freeDescriptorSet(dev_data, ds);
3852c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
3853c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    dev_data->descriptorPoolMap.erase(descriptorPool);
3854ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson    delete desc_pool_state;
3855c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
3856c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
3857bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
3858bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
385956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
3860a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    DESCRIPTOR_POOL_STATE *desc_pool_state = nullptr;
3861c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    VK_OBJECT obj_struct;
3862c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
3863c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = PreCallValidateDestroyDescriptorPool(dev_data, descriptorPool, &desc_pool_state, &obj_struct);
3864c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (!skip) {
3865c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.unlock();
3866c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        dev_data->dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
3867c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.lock();
3868405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptorPool != VK_NULL_HANDLE) {
3869405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyDescriptorPool(dev_data, descriptorPool, desc_pool_state, obj_struct);
3870405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
3871c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
38725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski// Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip result
3874bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If this is a secondary command buffer, then make sure its primary is also in-flight
3875bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If primary is not in-flight, then remove secondary from global in-flight set
3876bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// This function is only valid at a point when cmdBuffer is being reset or freed
3877cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action,
3878cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
38793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3880a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    if (cb_node->in_use.load()) {
3881a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3882a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                        HandleToUint64(cb_node->commandBuffer), __LINE__, error_code, "DS",
3883a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                        "Attempt to %s command buffer (0x%p) which is in use. %s", action, cb_node->commandBuffer,
3884a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                        validation_error_map[error_code]);
3885bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
38863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
3887bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
3888a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
3889bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Iterate over all cmdBuffers in given commandPool and verify that each is not in use
3890cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool, const char *action,
3891cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                        UNIQUE_VALIDATION_ERROR_CODE error_code) {
38923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3893a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
3894a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        skip |= checkCommandBufferInFlight(dev_data, GetCBNode(dev_data, cmd_buffer), action, error_code);
3895bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
38963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
3897bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
38985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3899bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
3900bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
390156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
39023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3903b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
3904c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
39055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < commandBufferCount; i++) {
39069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
39075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Delete CB information structure, and remove from commandBufferMap
39089f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
3909315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= checkCommandBufferInFlight(dev_data, cb_node, "free", VALIDATION_ERROR_2840005e);
3910c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        }
3911c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    }
3912c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
39133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
3914c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
39159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
3916c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    for (uint32_t i = 0; i < commandBufferCount; i++) {
39179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
3918c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        // Delete CB information structure, and remove from commandBufferMap
39199f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
39205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // reset prior to delete for data clean-up
3921a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            // TODO: fix this, it's insane.
39229f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            resetCB(dev_data, cb_node->commandBuffer);
39239f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->commandBufferMap.erase(cb_node->commandBuffer);
39249f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            delete cb_node;
39255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
39265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Remove commandBuffer reference from commandPoolMap
3928c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        pPool->commandBuffers.remove(pCommandBuffers[i]);
39295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3930b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
3931e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
39324a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
39335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
393589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
3936bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
393756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
39385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39394a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
39405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
3942b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
39435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
39445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
39455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
39475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
394989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
395089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
395156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
39520c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    bool skip = false;
39530c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (pCreateInfo && pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
39540c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        if (!dev_data->enabled_features.pipelineStatisticsQuery) {
39550c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
3956315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_11c0062e, "DS",
39570c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "Query pool with type VK_QUERY_TYPE_PIPELINE_STATISTICS created on a device "
39580c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "with VkDeviceCreateInfo.pEnabledFeatures.pipelineStatisticsQuery == VK_FALSE. %s",
3959315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_11c0062e]);
39600c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        }
39610c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
39620c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis
39630c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
39640c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (!skip) {
39650c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        result = dev_data->dispatch_table.CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
39660c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
39675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
3968b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
3969eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        QUERY_POOL_NODE *qp_node = &dev_data->queryPoolMap[*pQueryPool];
3970eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        qp_node->createInfo = *pCreateInfo;
39715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
39735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39755f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic bool PreCallValidateDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE **cp_state) {
39769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cp_state = GetCommandPoolNode(dev_data, pool);
3977cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_command_pool) return false;
39785f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = false;
39795f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (*cp_state) {
39805f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        // Verify that command buffers in pool are complete (not in-flight)
3981315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= checkCommandBuffersInFlight(dev_data, *cp_state, "destroy command pool with", VALIDATION_ERROR_24000052);
39825f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
39835f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    return skip;
39845f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
39855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39865f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic void PostCallRecordDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE *cp_state) {
39879f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandBufferMap
39885f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    for (auto cb : cp_state->commandBuffers) {
39899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, cb);
39907b34d10b918c1f69e7252174965c6a7a7c35ae05Chris Forbes        clear_cmd_buf_and_mem_references(dev_data, cb_node);
3991d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // Remove references to this cb_node prior to delete
3992d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // TODO : Need better solution here, resetCB?
39937165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        for (auto obj : cb_node->object_bindings) {
39947165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski            removeCommandBufferBinding(dev_data, &obj, cb_node);
39957165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        }
3996d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        for (auto framebuffer : cb_node->framebuffers) {
39979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
3998cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(cb_node);
3999d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        }
4000cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        dev_data->commandBufferMap.erase(cb);  // Remove this command buffer
4001cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        delete cb_node;                        // delete CB info structure
4002a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    }
40035f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    dev_data->commandPoolMap.erase(pool);
40045f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
4005e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
40065f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis// Destroy commandPool along with all of the commandBuffers allocated from that pool
40075f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
400856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
40095f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    COMMAND_POOL_NODE *cp_state = nullptr;
40105f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
40115f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = PreCallValidateDestroyCommandPool(dev_data, commandPool, &cp_state);
40125f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (!skip) {
40135f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.unlock();
40145f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        dev_data->dispatch_table.DestroyCommandPool(device, commandPool, pAllocator);
40155f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.lock();
4016405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (commandPool != VK_NULL_HANDLE) {
4017405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyCommandPool(dev_data, commandPool, cp_state);
4018405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
40195f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
40205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4022bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
402356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
40243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
4025400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
40261ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
40279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
4028315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= checkCommandBuffersInFlight(dev_data, pPool, "reset command pool with", VALIDATION_ERROR_32800050);
40291ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    lock.unlock();
4030a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes
40313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
40325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40334a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandPool(device, commandPool, flags);
40345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Reset all of the CBs allocated from this pool
40365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
40371ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.lock();
4038a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        for (auto cmdBuffer : pPool->commandBuffers) {
4039a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes            resetCB(dev_data, cmdBuffer);
40405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
40411ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.unlock();
40425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
40435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
40445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
404689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
404756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
40483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
4049b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
40505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < fenceCount; ++i) {
40519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, pFences[i]);
4052090da73358f71ba026e2474a822fecf55267d166Chris Forbes        if (pFence && pFence->state == FENCE_INFLIGHT) {
4053315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |=
4054315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
4055315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pFences[i]), __LINE__, VALIDATION_ERROR_32e008c6, "DS", "Fence 0x%" PRIx64 " is in use. %s",
4056315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pFences[i]), validation_error_map[VALIDATION_ERROR_32e008c6]);
40575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
40585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4059b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4060090da73358f71ba026e2474a822fecf55267d166Chris Forbes
40613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4062090da73358f71ba026e2474a822fecf55267d166Chris Forbes
40634a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetFences(device, fenceCount, pFences);
4064090da73358f71ba026e2474a822fecf55267d166Chris Forbes
4065090da73358f71ba026e2474a822fecf55267d166Chris Forbes    if (result == VK_SUCCESS) {
4066090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.lock();
4067090da73358f71ba026e2474a822fecf55267d166Chris Forbes        for (uint32_t i = 0; i < fenceCount; ++i) {
40689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pFence = GetFenceNode(dev_data, pFences[i]);
4069090da73358f71ba026e2474a822fecf55267d166Chris Forbes            if (pFence) {
4070090da73358f71ba026e2474a822fecf55267d166Chris Forbes                pFence->state = FENCE_UNSIGNALED;
4071090da73358f71ba026e2474a822fecf55267d166Chris Forbes            }
4072090da73358f71ba026e2474a822fecf55267d166Chris Forbes        }
4073090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.unlock();
4074090da73358f71ba026e2474a822fecf55267d166Chris Forbes    }
4075090da73358f71ba026e2474a822fecf55267d166Chris Forbes
40765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
40775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4079e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis// For given cb_nodes, invalidate them and track object causing invalidation
40800a4087f99558069e9f6a437ff2dbb5a9c1c22ccaTobin Ehlisvoid invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj) {
4081e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    for (auto cb_node : cb_nodes) {
408239c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        if (cb_node->state == CB_RECORDING) {
408339c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
40849b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
4085226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "Invalidating a command buffer that's currently being recorded: 0x%p.", cb_node->commandBuffer);
408639c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        }
4087e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->state = CB_INVALID;
4088e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->broken_bindings.push_back(obj);
4089db365f522319df6446b50584277a3bbfee1c1052Chris Forbes
4090db365f522319df6446b50584277a3bbfee1c1052Chris Forbes        // if secondary, then propagate the invalidation to the primaries that will call us.
4091db365f522319df6446b50584277a3bbfee1c1052Chris Forbes        if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {
4092db365f522319df6446b50584277a3bbfee1c1052Chris Forbes            invalidateCommandBuffers(dev_data, cb_node->linkedCommandBuffers, obj);
4093db365f522319df6446b50584277a3bbfee1c1052Chris Forbes        }
4094e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    }
4095e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis}
4096e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis
4097c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool PreCallValidateDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer,
4098c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis                                              FRAMEBUFFER_STATE **framebuffer_state, VK_OBJECT *obj_struct) {
40999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *framebuffer_state = GetFramebufferState(dev_data, framebuffer);
41009b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(framebuffer), kVulkanObjectTypeFramebuffer};
4101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_framebuffer) return false;
4102728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = false;
4103728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (*framebuffer_state) {
4104315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *framebuffer_state, *obj_struct, VALIDATION_ERROR_250006f8);
4105728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    }
4106728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    return skip;
4107728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
4108728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
4109c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void PostCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
4110728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis                                             VK_OBJECT obj_struct) {
411139c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, framebuffer_state->cb_bindings, obj_struct);
4112728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    dev_data->frameBufferMap.erase(framebuffer);
4113728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
4114728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
4115bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
411656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4117c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    FRAMEBUFFER_STATE *framebuffer_state = nullptr;
4118728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    VK_OBJECT obj_struct;
4119b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4120728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = PreCallValidateDestroyFramebuffer(dev_data, framebuffer, &framebuffer_state, &obj_struct);
4121728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (!skip) {
4122728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.unlock();
4123728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        dev_data->dispatch_table.DestroyFramebuffer(device, framebuffer, pAllocator);
4124728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.lock();
4125405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (framebuffer != VK_NULL_HANDLE) {
4126405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyFramebuffer(dev_data, framebuffer, framebuffer_state, obj_struct);
4127405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
41285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
41305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
41310ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic bool PreCallValidateDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE **rp_state,
41320ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                             VK_OBJECT *obj_struct) {
41339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *rp_state = GetRenderPassState(dev_data, render_pass);
41349b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(render_pass), kVulkanObjectTypeRenderPass};
4135cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_renderpass) return false;
41360ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = false;
41370ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    if (*rp_state) {
4138315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *rp_state, *obj_struct, VALIDATION_ERROR_264006d2);
41390ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    }
41400ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    return skip;
41410ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
41420ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
41430ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic void PostCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
41440ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                            VK_OBJECT obj_struct) {
414539c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, rp_state->cb_bindings, obj_struct);
41460ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    dev_data->renderPassMap.erase(render_pass);
41470ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
41480ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
4149bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
415056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
41510ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    RENDER_PASS_STATE *rp_state = nullptr;
41520ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    VK_OBJECT obj_struct;
4153e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
41540ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = PreCallValidateDestroyRenderPass(dev_data, renderPass, &rp_state, &obj_struct);
4155a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    if (!skip) {
4156a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis        lock.unlock();
41574a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
41580ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        lock.lock();
4159405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (renderPass != VK_NULL_HANDLE) {
4160405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyRenderPass(dev_data, renderPass, rp_state, obj_struct);
4161405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
4162a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    }
41635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
41645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
416589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
416689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
416756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
41683683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
41693683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    bool skip = PreCallValidateCreateBuffer(dev_data, pCreateInfo);
41703683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    lock.unlock();
41713683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
41723683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
41734a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
41745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
41755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
41763683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.lock();
41773683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBuffer(dev_data, pCreateInfo, pBuffer);
41783683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.unlock();
41795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
41815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
41825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
418389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
418489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
418556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
41868c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
41873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateCreateBufferView(dev_data, pCreateInfo);
41888c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
41893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
41904a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBufferView(device, pCreateInfo, pAllocator, pView);
41915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
41928c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
41933683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBufferView(dev_data, pCreateInfo, pView);
41948c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
41955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
41975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
41985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
41998dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski// Access helper functions for external modules
4200d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkFormatProperties *GetFormatProperties(core_validation::layer_data *device_data, VkFormat format) {
4201d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkFormatProperties *format_properties = new VkFormatProperties;
4202d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
4203d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
4204d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, format_properties);
4205d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return format_properties;
42068dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
42078dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
4208d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkImageFormatProperties *GetImageFormatProperties(core_validation::layer_data *device_data, VkFormat format,
4209d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageType image_type, VkImageTiling tiling, VkImageUsageFlags usage,
4210d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageCreateFlags flags) {
4211d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkImageFormatProperties *image_format_properties = new VkImageFormatProperties;
4212d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
4213d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
4214d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceImageFormatProperties(device_data->physical_device, format, image_type, tiling,
4215d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                                         usage, flags, image_format_properties);
4216d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return image_format_properties;
42178dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
42188dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
42197a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlisconst debug_report_data *GetReportData(const core_validation::layer_data *device_data) { return device_data->report_data; }
42208dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
42218dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinskiconst VkPhysicalDeviceProperties *GetPhysicalDeviceProperties(core_validation::layer_data *device_data) {
42228dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    return &device_data->phys_dev_props;
42238dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
42248dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
42258c59133586421be878d393799b30044497f77727Mark Lobodzinskiconst CHECK_DISABLED *GetDisables(core_validation::layer_data *device_data) { return &device_data->instance_data->disabled; }
42268c59133586421be878d393799b30044497f77727Mark Lobodzinski
42278c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> *GetImageMap(core_validation::layer_data *device_data) {
42288c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageMap;
42298c59133586421be878d393799b30044497f77727Mark Lobodzinski}
42308c59133586421be878d393799b30044497f77727Mark Lobodzinski
42318c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *GetImageSubresourceMap(core_validation::layer_data *device_data) {
42328c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageSubresourceMap;
42338c59133586421be878d393799b30044497f77727Mark Lobodzinski}
42348c59133586421be878d393799b30044497f77727Mark Lobodzinski
42358c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *GetImageLayoutMap(layer_data *device_data) {
42368c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageLayoutMap;
42378c59133586421be878d393799b30044497f77727Mark Lobodzinski}
42388c59133586421be878d393799b30044497f77727Mark Lobodzinski
42390db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlisstd::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const *GetImageLayoutMap(layer_data const *device_data) {
42400db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis    return &device_data->imageLayoutMap;
42410db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis}
42420db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis
42433683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>> *GetBufferMap(layer_data *device_data) {
42443683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferMap;
42453683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
42463683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
42473683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>> *GetBufferViewMap(layer_data *device_data) {
42483683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferViewMap;
42493683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
42503683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
42511c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinskistd::unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>> *GetImageViewMap(layer_data *device_data) {
42521c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski    return &device_data->imageViewMap;
42531c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski}
42541c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski
4255d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst PHYS_DEV_PROPERTIES_NODE *GetPhysDevProperties(const layer_data *device_data) {
42566a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    return &device_data->phys_dev_properties;
42576a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski}
42586a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski
42595f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinskiconst VkPhysicalDeviceFeatures *GetEnabledFeatures(const layer_data *device_data) {
42605f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski    return &device_data->enabled_features;
42615f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski}
42625f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski
4263a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinskiconst DeviceExtensions *GetDeviceExtensions(const layer_data *device_data) { return &device_data->extensions; }
42640e2296e24065d02615ee87561bbb80af414a1ddfMike Schuchardt
426589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
426689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
42678dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
426856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
42698dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    bool skip = PreCallValidateCreateImage(dev_data, pCreateInfo, pAllocator, pImage);
42708dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    if (!skip) {
42718dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski        result = dev_data->dispatch_table.CreateImage(device, pCreateInfo, pAllocator, pImage);
42728dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    }
42735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
4274b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
4275920311b6aa5614a545cad59521770d0898a75d65Mark Lobodzinski        PostCallRecordCreateImage(dev_data, pCreateInfo, pImage);
42765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
42775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
42785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
42808c07a094dc9cc4afb6b62181f341c12b9e969041Mark YoungVKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
42818c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
428256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
42838c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
4284e3effabf8e97cae8e006477806ceaca62e4f2ce7Tobin Ehlis    bool skip = PreCallValidateCreateImageView(dev_data, pCreateInfo);
42858c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
4286cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
42874a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateImageView(device, pCreateInfo, pAllocator, pView);
42885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
42898c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
429079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        PostCallRecordCreateImageView(dev_data, pCreateInfo, *pView);
42918c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
42925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4293bb6624cb996175d8945190886a200e720b3871efChris Forbes
42945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
42955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4297bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo,
4298bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
429956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
43004a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFence(device, pCreateInfo, pAllocator, pFence);
43015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
4302b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
4303a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        auto &fence_node = dev_data->fenceMap[*pFence];
43048988ad37ea5a054ff2ae3cbe4b767ae6c13cf48bChris Forbes        fence_node.fence = *pFence;
4305a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        fence_node.createInfo = *pCreateInfo;
4306cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        fence_node.state = (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) ? FENCE_RETIRED : FENCE_UNSIGNALED;
43075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
43095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO handle pipeline caches
431289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
431389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
431456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
43154a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
43165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
43175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4319bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache,
4320bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkAllocationCallbacks *pAllocator) {
432156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
43224a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineCache(device, pipelineCache, pAllocator);
43235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4325bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize,
4326bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    void *pData) {
432756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
43284a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
43295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
43305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4332bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount,
4333bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   const VkPipelineCache *pSrcCaches) {
433456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
43354a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
43365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
43375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43393d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis// utility function to set collective state for pipeline
43404c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisvoid set_pipeline_state(PIPELINE_STATE *pPipe) {
43413d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // If any attachment used by this pipeline has blendEnable, set top-level blendEnable
43423d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->graphicsPipelineCI.pColorBlendState) {
43433d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        for (size_t i = 0; i < pPipe->attachments.size(); ++i) {
43443d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (VK_TRUE == pPipe->attachments[i].blendEnable) {
43453d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                if (((pPipe->attachments[i].dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
43463d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
43473d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
43483d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
43493d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
43503d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
43513d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
43523d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
43533d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    pPipe->blendConstantsEnabled = true;
43543d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                }
43553d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            }
43563d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        }
43573d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
43583d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis}
43593d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis
4360daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinskibool validate_dual_src_blend_feature(layer_data *device_data, PIPELINE_STATE *pipe_state) {
4361daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    bool skip = false;
4362daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    if (pipe_state->graphicsPipelineCI.pColorBlendState) {
4363daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski        for (size_t i = 0; i < pipe_state->attachments.size(); ++i) {
4364daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            if (!device_data->enabled_features.dualSrcBlend) {
4365daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                if ((pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
4366daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
4367daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
4368daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA) ||
4369daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
4370daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
4371daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
4372daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA)) {
4373daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    skip |=
4374daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
43759b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pipe_state->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
4376daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                "CmdBindPipeline: vkPipeline (0x%" PRIxLEAST64 ") attachment[" PRINTF_SIZE_T_SPECIFIER
4377daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                "] has a dual-source blend factor but this device feature is not enabled.",
43789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pipe_state->pipeline), i);
4379daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                }
4380daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            }
4381daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski        }
4382daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    }
4383daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    return skip;
4384daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski}
4385daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski
438648b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinskistatic bool PreCallCreateGraphicsPipelines(layer_data *device_data, uint32_t count,
438748b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski                                           const VkGraphicsPipelineCreateInfo *create_infos, vector<PIPELINE_STATE *> &pipe_state) {
438848b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    bool skip = false;
4389bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    instance_layer_data *instance_data =
439056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
439148b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
439248b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    for (uint32_t i = 0; i < count; i++) {
439348b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski        skip |= verifyPipelineCreateState(device_data, pipe_state, i);
439478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        if (create_infos[i].pVertexInputState != NULL) {
439578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            for (uint32_t j = 0; j < create_infos[i].pVertexInputState->vertexAttributeDescriptionCount; j++) {
439678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormat format = create_infos[i].pVertexInputState->pVertexAttributeDescriptions[j].format;
439778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                // Internal call to get format info.  Still goes through layers, could potentially go directly to ICD.
439878b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormatProperties properties;
439978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, &properties);
440078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                if ((properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0) {
440178b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                    skip |= log_msg(
440278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4403315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        __LINE__, VALIDATION_ERROR_14a004de, "IMAGE",
440478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "vkCreateGraphicsPipelines: pCreateInfo[%d].pVertexInputState->vertexAttributeDescriptions[%d].format "
440578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "(%s) is not a supported vertex buffer format. %s",
4406315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        i, j, string_VkFormat(format), validation_error_map[VALIDATION_ERROR_14a004de]);
440778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                }
440878b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            }
440978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        }
441048b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    }
441148b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    return skip;
441248b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski}
441348b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
4414bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
4415bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
4416bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
44175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO What to do with pipelineCache?
44185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // The order of operations here is a little convoluted but gets the job done
44194c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    //  1. Pipeline create state is first shadowed into PIPELINE_STATE struct
44205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  2. Create state is then validated (which uses flags setup during shadowing)
44215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
442242486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    bool skip = false;
44235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
442442486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    vector<PIPELINE_STATE *> pipe_state(count);
442556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
44265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
4428b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
44295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
443142486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i] = new PIPELINE_STATE;
443242486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->initGraphicsPipeline(&pCreateInfos[i]);
44339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        pipe_state[i]->render_pass_ci.initialize(GetRenderPassState(dev_data, pCreateInfos[i].renderPass)->createInfo.ptr());
443442486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
44355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
443642486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    skip |= PreCallCreateGraphicsPipelines(dev_data, count, pCreateInfos, pipe_state);
44375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4438c70226063be6148056ceeccf835175a1fd59f24fChris Forbes    if (skip) {
4439c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        for (i = 0; i < count; i++) {
4440c70226063be6148056ceeccf835175a1fd59f24fChris Forbes            delete pipe_state[i];
44411ab616b32d4e5b7d62d4a8c41b0c03ea335ab845Chris Forbes            pPipelines[i] = VK_NULL_HANDLE;
4442c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        }
44437a456d188475c23b566334be45dc0489b2789653Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
44447a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
44457a456d188475c23b566334be45dc0489b2789653Chris Forbes
44467a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
4447bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
4448bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
44497a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
44507a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
445161943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
445261943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            delete pipe_state[i];
4453bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
445461943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            pipe_state[i]->pipeline = pPipelines[i];
445561943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            dev_data->pipelineMap[pipe_state[i]->pipeline] = pipe_state[i];
445661943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        }
44575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4458c70226063be6148056ceeccf835175a1fd59f24fChris Forbes
44595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
44605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
44615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4462bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
4463bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkComputePipelineCreateInfo *pCreateInfos,
4464bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
44650108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes    bool skip = false;
44665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
44684c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    vector<PIPELINE_STATE *> pPipeState(count);
446956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
44705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
4472b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
44735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
44745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Verify compute stage bits
44755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Create and initialize internal tracking data structure
44774c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i] = new PIPELINE_STATE;
44784c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i]->initComputePipeline(&pCreateInfos[i]);
4479c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis        pPipeState[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
44805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Add Compute Pipeline Verification
4482e446ad08318228362ef35d73e7a0636075cb3636Chris Forbes        skip |= validate_compute_pipeline(dev_data, pPipeState[i]);
44830108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes        // skip |= verifyPipelineCreateState(dev_data, pPipeState[i]);
44845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
44855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44867a456d188475c23b566334be45dc0489b2789653Chris Forbes    if (skip) {
44875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < count; i++) {
44885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Clean up any locally allocated data structures
44894c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis            delete pPipeState[i];
4490fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipelines[i] = VK_NULL_HANDLE;
44915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
44925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
44935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
44947a456d188475c23b566334be45dc0489b2789653Chris Forbes
44957a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
4496bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
4497bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
44987a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
44997a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
4500fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
4501fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            delete pPipeState[i];
4502bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
4503fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipeState[i]->pipeline = pPipelines[i];
4504fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            dev_data->pipelineMap[pPipeState[i]->pipeline] = pPipeState[i];
4505fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        }
45067a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
45077a456d188475c23b566334be45dc0489b2789653Chris Forbes
45085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
45095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
451189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
451289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
451356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
45144a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSampler(device, pCreateInfo, pAllocator, pSampler);
45155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
4516b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
4517d31a44af6da568692a73201825459689c9431867Tobin Ehlis        dev_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_STATE>(new SAMPLER_STATE(pSampler, pCreateInfo));
45185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
45195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
45205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
45220c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic bool PreCallValidateCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info) {
4523cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.create_descriptor_set_layout) return false;
45240c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    return cvdescriptorset::DescriptorSetLayout::ValidateCreateInfo(dev_data->report_data, create_info);
45250c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
45260c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
45270c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic void PostCallRecordCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info,
45280c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis                                                    VkDescriptorSetLayout set_layout) {
4529c8bee427d7a8ed0ccec899fbf47134d582dcafbdGabríel Arthúr Pétursson    dev_data->descriptorSetLayoutMap[set_layout] = std::unique_ptr<cvdescriptorset::DescriptorSetLayout>(
4530c8bee427d7a8ed0ccec899fbf47134d582dcafbdGabríel Arthúr Pétursson        new cvdescriptorset::DescriptorSetLayout(create_info, set_layout));
45310c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
45320c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
4533bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
4534bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator,
4535bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VkDescriptorSetLayout *pSetLayout) {
453656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
45370c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
45380c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
45390c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    bool skip = PreCallValidateCreateDescriptorSetLayout(dev_data, pCreateInfo);
45400c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    if (!skip) {
45410c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        lock.unlock();
45420c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        result = dev_data->dispatch_table.CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
45430c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        if (VK_SUCCESS == result) {
45440c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            lock.lock();
45450c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            PostCallRecordCreateDescriptorSetLayout(dev_data, pCreateInfo, *pSetLayout);
45460c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        }
45475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
45485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
45495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
45519e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Used by CreatePipelineLayout and CmdPushConstants.
45529e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Note that the index argument is optional and only used by CreatePipelineLayout.
45539e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultzstatic bool validatePushConstantRange(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
45549e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz                                      const char *caller_name, uint32_t index = 0) {
4555cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.push_constant_range) return false;
45569e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    uint32_t const maxPushConstantsSize = dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize;
45573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
45589e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Check that offset + size don't exceed the max.
45599e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Prevent arithetic overflow here by avoiding addition and testing in this order.
45609e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset >= maxPushConstantsSize) || (size > maxPushConstantsSize - offset)) {
45619e24d8153ab63bc3ac08b5a1517c203930b5de91Karl 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.
45629e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
4563e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (offset >= maxPushConstantsSize) {
45643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4565315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a0024c, "DS",
45663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with offset %u that "
45673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "exceeds this device's maxPushConstantSize of %u. %s",
4568315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_11a0024c]);
4569e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
4570e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (size > maxPushConstantsSize - offset) {
4571315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4572315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a00254, "DS",
4573315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "%s call has push constants index %u with offset %u and size %u that "
4574315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "exceeds this device's maxPushConstantSize of %u. %s",
4575315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, size, maxPushConstantsSize,
4576315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_11a00254]);
4577e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
45789e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
45794527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (offset >= maxPushConstantsSize) {
45803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4581315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc002e4, "DS",
45823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with offset %u that "
45833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "exceeds this device's maxPushConstantSize of %u. %s",
4584315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_1bc002e4]);
45854527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
45864527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size > maxPushConstantsSize - offset) {
4587315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4588315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc002e6, "DS",
4589315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "%s call has push constants index %u with offset %u and size %u that "
4590315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "exceeds this device's maxPushConstantSize of %u. %s",
4591315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, size, maxPushConstantsSize,
4592315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_1bc002e6]);
45934527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
45949e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
45953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
45963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
45979e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
45989e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
45999e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // size needs to be non-zero and a multiple of 4.
46009e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((size == 0) || ((size & 0x3) != 0)) {
46019e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
4602891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size == 0) {
46033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4604315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a00250, "DS",
46053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
46063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be greater than zero. %s",
4607315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_11a00250]);
4608891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
4609891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size & 0x3) {
46103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4611315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a00252, "DS",
46123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
46133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be a multiple of 4. %s",
4614315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_11a00252]);
4615891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
46169e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
46174527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size == 0) {
46183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4619315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc2c21b, "DS",
46203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
46213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be greater than zero. %s",
4622315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_1bc2c21b]);
46234527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
46244527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size & 0x3) {
46253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4626315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc002e2, "DS",
46273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
46283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be a multiple of 4. %s",
4629315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_1bc002e2]);
46304527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
46319e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
46323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
46333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
46349e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
46359e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
46369e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // offset needs to be a multiple of 4.
46379e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset & 0x3) != 0) {
46389e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
46393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4640315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_11a0024e, "DS",
46413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s call has push constants index %u with "
46423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "offset %u. Offset must be a multiple of 4. %s",
4643315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            caller_name, index, offset, validation_error_map[VALIDATION_ERROR_11a0024e]);
46449e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
46453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4646315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_1bc002e0, "DS",
46473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s call has push constants with "
46483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "offset %u. Offset must be a multiple of 4. %s",
4649315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            caller_name, offset, validation_error_map[VALIDATION_ERROR_1bc002e0]);
46509e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
46513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
46523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
46539e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
46545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
46553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
46565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4658bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
465989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                    const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
46603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
466156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4662bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // TODO : Add checks for VALIDATION_ERRORS 865-870
46639e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Push Constant Range checks
466407a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    uint32_t i, j;
46655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
46663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validatePushConstantRange(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
46673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                          pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()", i);
46689e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == pCreateInfo->pPushConstantRanges[i].stageFlags) {
46693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4670315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_11a2dc03, "DS", "vkCreatePipelineLayout() call has no stageFlags set. %s",
4671315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_11a2dc03]);
46729e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
46739e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
46743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
467507a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz
4676bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl 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.
467707a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
467807a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz        for (j = i + 1; j < pCreateInfo->pushConstantRangeCount; ++j) {
4679bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz            if (0 != (pCreateInfo->pPushConstantRanges[i].stageFlags & pCreateInfo->pPushConstantRanges[j].stageFlags)) {
46803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
4681315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_0fe00248, "DS",
46823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "vkCreatePipelineLayout() Duplicate stage flags found in ranges %d and %d. %s", i, j,
4683315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_0fe00248]);
46849e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz            }
46855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
46865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4687f73b2046273413ea1338dd714d67c39f8e0fa09eChris Forbes
46884a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
46895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
4690b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
46915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
469269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        plNode.layout = *pPipelineLayout;
4693416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.set_layouts.resize(pCreateInfo->setLayoutCount);
46945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
46959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            plNode.set_layouts[i] = GetDescriptorSetLayout(dev_data, pCreateInfo->pSetLayouts[i]);
46965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4697416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.push_constant_ranges.resize(pCreateInfo->pushConstantRangeCount);
46985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
4699416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            plNode.push_constant_ranges[i] = pCreateInfo->pPushConstantRanges[i];
47005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
47025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
47035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4705bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
4706bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) {
470756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
47084a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
47095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
4710a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis        DESCRIPTOR_POOL_STATE *pNewNode = new DESCRIPTOR_POOL_STATE(*pDescriptorPool, pCreateInfo);
47115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (NULL == pNewNode) {
47125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
47139b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(*pDescriptorPool), __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
4714a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                        "Out of memory while attempting to allocate DESCRIPTOR_POOL_STATE in vkCreateDescriptorPool()"))
47155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return VK_ERROR_VALIDATION_FAILED_EXT;
47165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
4717b9e992386a44404152747d66817a733aa127e281Jeremy Hayes            std::lock_guard<std::mutex> lock(global_lock);
47185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
47195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
47215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Need to do anything if pool create fails?
47225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
47235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
47245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4726bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
4727bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDescriptorPoolResetFlags flags) {
4728315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    // TODO : Add checks for VALIDATION_ERROR_32a00272
472956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
47304a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetDescriptorPool(device, descriptorPool, flags);
47315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
4732b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
47335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        clearDescriptorPool(dev_data, device, descriptorPool, flags);
47345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
47355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
47365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47372c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes// Ensure the pool contains enough descriptors and descriptor sets to satisfy
4738789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// an allocation request. Fills common_data with the total number of descriptors of each type required,
4739789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// as well as DescriptorSetLayout ptrs used for later update.
47407f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlisstatic bool PreCallValidateAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
47417f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                  cvdescriptorset::AllocateDescriptorSetsData *common_data) {
47427a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    // Always update common data
47437a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    cvdescriptorset::UpdateAllocateDescriptorSetsData(dev_data, pAllocateInfo, common_data);
4744cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.allocate_descriptor_sets) return false;
47457e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All state checks for AllocateDescriptorSets is done in single function
47467a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    return cvdescriptorset::ValidateAllocateDescriptorSets(dev_data, pAllocateInfo, common_data);
47477e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis}
47487e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis// Allocation state was good and call down chain was made so update state based on allocating descriptor sets
47497e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlisstatic void PostCallRecordAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
47507f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 VkDescriptorSet *pDescriptorSets,
47517f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 const cvdescriptorset::AllocateDescriptorSetsData *common_data) {
47527e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All the updates are contained in a single cvdescriptorset function
47532c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    cvdescriptorset::PerformAllocateDescriptorSets(pAllocateInfo, pDescriptorSets, common_data, &dev_data->descriptorPoolMap,
4754b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                                                   &dev_data->setMap, dev_data);
47552c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes}
47562c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes
4757bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
4758bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkDescriptorSet *pDescriptorSets) {
475956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4760b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
47617f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    cvdescriptorset::AllocateDescriptorSetsData common_data(pAllocateInfo->descriptorSetCount);
47623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateAllocateDescriptorSets(dev_data, pAllocateInfo, &common_data);
4763b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4764d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
47653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4766d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
47674a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
47686511ce241f7f210211e0c0e882f3c14889071f4dChris Forbes
47695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
4770b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
47717f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis        PostCallRecordAllocateDescriptorSets(dev_data, pAllocateInfo, pDescriptorSets, &common_data);
4772b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
47735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
47745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
47755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4776cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Verify state before freeing DescriptorSets
4777cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic bool PreCallValidateFreeDescriptorSets(const layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
4778cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                              const VkDescriptorSet *descriptor_sets) {
4779cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_descriptor_sets) return false;
47803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
4781cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // First make sure sets being destroyed are not currently in-use
4782405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    for (uint32_t i = 0; i < count; ++i) {
4783405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
47843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateIdleDescriptorSet(dev_data, descriptor_sets[i], "vkFreeDescriptorSets");
4785405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
4786405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    }
4787cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
47889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
4789a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    if (pool_state && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pool_state->createInfo.flags)) {
4790cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        // Can't Free from a NON_FREE pool
47913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
4792315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pool), __LINE__, VALIDATION_ERROR_28600270, "DS",
47933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
47943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT. %s",
4795315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_28600270]);
4796cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
47973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
4798cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
4799cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Sets have been removed from the pool so update underlying state
4800cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic void PostCallRecordFreeDescriptorSets(layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
4801cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                             const VkDescriptorSet *descriptor_sets) {
48029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
4803cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // Update available descriptor sets in pool
4804cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    pool_state->availableSets += count;
4805cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
4806cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // For each freed descriptor add its resources back into the pool as available and remove from pool and setMap
4807cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    for (uint32_t i = 0; i < count; ++i) {
4808405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
4809405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            auto descriptor_set = dev_data->setMap[descriptor_sets[i]];
4810405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            uint32_t type_index = 0, descriptor_count = 0;
4811405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            for (uint32_t j = 0; j < descriptor_set->GetBindingCount(); ++j) {
4812405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                type_index = static_cast<uint32_t>(descriptor_set->GetTypeFromIndex(j));
4813405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                descriptor_count = descriptor_set->GetDescriptorCountFromIndex(j);
4814405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                pool_state->availableDescriptorTypeCount[type_index] += descriptor_count;
4815405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            }
4816405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            freeDescriptorSet(dev_data, descriptor_set);
4817405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            pool_state->sets.erase(descriptor_set);
4818405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
4819cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
4820cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
48215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4822bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
4823bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkDescriptorSet *pDescriptorSets) {
482456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
48255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Make sure that no sets being destroyed are in-flight
4826b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
48273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
4828b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4829e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
48303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
48314a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
48325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
4833b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
4834cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        PostCallRecordFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
4835b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
48365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
48375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
48385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48396b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// TODO : This is a Proof-of-concept for core validation architecture
48406b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  Really we'll want to break out these functions to separate files but
48416b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  keeping it all together here to prove out design
48426b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PreCallValidate* handles validating all of the state prior to calling down chain to UpdateDescriptorSets()
48436b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic bool PreCallValidateUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
48446b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
48456b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkCopyDescriptorSet *pDescriptorCopies) {
4846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.update_descriptor_sets) return false;
48476b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // First thing to do is perform map look-ups.
48486b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // NOTE : UpdateDescriptorSets is somewhat unique in that it's operating on a number of DescriptorSets
48496b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  so we can't just do a single map look-up up-front, but do them individually in functions below
48506b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis
48516b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Now make call(s) that validate state, but don't perform state updates in this function
48526b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Note, here DescriptorSets is unique in that we don't yet have an instance. Using a helper function in the
48536b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  namespace which will parse params and make calls into specific class instances
4854104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return cvdescriptorset::ValidateUpdateDescriptorSets(dev_data->report_data, dev_data, descriptorWriteCount, pDescriptorWrites,
4855104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis                                                         descriptorCopyCount, pDescriptorCopies);
48566b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
48576b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSets()
48586b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic void PostCallRecordUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
48596b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
48606b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkCopyDescriptorSet *pDescriptorCopies) {
4861104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    cvdescriptorset::PerformUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
48626b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                 pDescriptorCopies);
48636b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
48645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4865bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
4866bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
4867bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkCopyDescriptorSet *pDescriptorCopies) {
48686b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Only map look-up at top level is for device-level layer_data
486956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4870b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
48713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
48723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                    pDescriptorCopies);
4873b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
48743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
48754a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
48764a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                      pDescriptorCopies);
48776b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        lock.lock();
48786b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        // Since UpdateDescriptorSets() is void, nothing to check prior to updating state
48796b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        PostCallRecordUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
48806b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                           pDescriptorCopies);
48815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
48825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4884bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo,
4885bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkCommandBuffer *pCommandBuffer) {
488656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
48874a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
48885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
4889b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::unique_lock<std::mutex> lock(global_lock);
48909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pPool = GetCommandPoolNode(dev_data, pCreateInfo->commandPool);
4891cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes
4892cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes        if (pPool) {
489372d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
48945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to its commandPool map
4895cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes                pPool->commandBuffers.push_back(pCommandBuffer[i]);
48965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
48975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to map
48985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
48995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                resetCB(dev_data, pCommandBuffer[i]);
49005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->createInfo = *pCreateInfo;
49015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->device = device;
49025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
49035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4904b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
49055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
49065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
49075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4909883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis// Add bindings between the given cmd buffer & framebuffer and the framebuffer's children
4910c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void AddFramebufferBinding(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, FRAMEBUFFER_STATE *fb_state) {
49119b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    addCommandBufferBinding(&fb_state->cb_bindings, {HandleToUint64(fb_state->framebuffer), kVulkanObjectTypeFramebuffer},
49120245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            cb_state);
4913883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    for (auto attachment : fb_state->attachments) {
4914883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        auto view_state = attachment.view_state;
4915883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (view_state) {
491603ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis            AddCommandBufferBindingImageView(dev_data, cb_state, view_state);
4917883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
49189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto rp_state = GetRenderPassState(dev_data, fb_state->createInfo.renderPass);
4919883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (rp_state) {
49209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            addCommandBufferBinding(&rp_state->cb_bindings, {HandleToUint64(rp_state->renderPass), kVulkanObjectTypeRenderPass},
49219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    cb_state);
4922883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
4923883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    }
4924883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis}
4925883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis
4926bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
49273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
492856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
4929b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
49305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate command buffer level
49319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
4932f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
49335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
4934a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        if (cb_node->in_use.load()) {
49353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4936315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00062, "MEM",
493759ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis                            "Calling vkBeginCommandBuffer() on active command buffer %p before it has completed. "
49383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "You must check command buffer fence before this call. %s",
4939315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            commandBuffer, validation_error_map[VALIDATION_ERROR_16e00062]);
49405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4941f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, cb_node);
4942f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
49435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary Command Buffer
49445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
49455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!pInfo) {
49463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
49475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4948315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00066, "DS",
4949bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must have inheritance info. %s", commandBuffer,
4950315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_16e00066]);
49515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
49525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
49532c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->renderPass);
49542c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    string errorString = "";
49559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto framebuffer = GetFramebufferState(dev_data, pInfo->framebuffer);
49562c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    if (framebuffer) {
49572c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        if ((framebuffer->createInfo.renderPass != pInfo->renderPass) &&
49582c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            !verify_renderpass_compatibility(dev_data, framebuffer->renderPassCreateInfo.ptr(),
49599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                             GetRenderPassState(dev_data, pInfo->renderPass)->createInfo.ptr(),
49602c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                             errorString)) {
49612c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            // renderPass that framebuffer was created with must be compatible with local renderPass
49623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
49639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
4964315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                            VALIDATION_ERROR_0280006e, "DS",
49653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "vkBeginCommandBuffer(): Secondary Command "
49663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "Buffer (0x%p) renderPass (0x%" PRIxLEAST64
49673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            ") is incompatible w/ framebuffer "
49683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "(0x%" PRIxLEAST64 ") w/ render pass (0x%" PRIxLEAST64 ") due to: %s. %s",
49699b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                            commandBuffer, HandleToUint64(pInfo->renderPass), HandleToUint64(pInfo->framebuffer),
49709b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                            HandleToUint64(framebuffer->createInfo.renderPass), errorString.c_str(),
4971315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                            validation_error_map[VALIDATION_ERROR_0280006e]);
49725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
49732c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        // Connect this framebuffer and its children to this cmdBuffer
49742c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        AddFramebufferBinding(dev_data, cb_node, framebuffer);
49755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
49765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
49774527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                if ((pInfo->occlusionQueryEnable == VK_FALSE || dev_data->enabled_features.occlusionQueryPrecise == VK_FALSE) &&
49785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
49793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
49809b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
4981315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    VALIDATION_ERROR_16e00068, "DS",
49823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must not have "
49833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not "
49843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "support precise occlusion queries. %s",
4985315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    commandBuffer, validation_error_map[VALIDATION_ERROR_16e00068]);
49865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
49875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
49885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
49899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto renderPass = GetRenderPassState(dev_data, pInfo->renderPass);
499016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                if (renderPass) {
4991fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    if (pInfo->subpass >= renderPass->createInfo.subpassCount) {
49923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
49939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
4994315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        VALIDATION_ERROR_0280006c, "DS",
49953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        "vkBeginCommandBuffer(): Secondary Command Buffers (0x%p) must have a subpass index (%d) "
49963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        "that is less than the number of subpasses (%d). %s",
49973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        commandBuffer, pInfo->subpass, renderPass->createInfo.subpassCount,
4998315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        validation_error_map[VALIDATION_ERROR_0280006c]);
49995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
50005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
50015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
50025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5003f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (CB_RECORDING == cb_node->state) {
50043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5005315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00062, "DS",
50063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkBeginCommandBuffer(): Cannot call Begin on command buffer (0x%p"
50073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") in the RECORDING state. Must first call vkEndCommandBuffer(). %s",
5008315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            commandBuffer, validation_error_map[VALIDATION_ERROR_16e00062]);
5009347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        } else if (CB_RECORDED == cb_node->state || (CB_INVALID == cb_node->state && CMD_END == cb_node->last_cmd)) {
5010f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            VkCommandPool cmdPool = cb_node->createInfo.commandPool;
50119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pPool = GetCommandPoolNode(dev_data, cmdPool);
5012cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes            if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
50133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
50145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5015315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00064, "DS",
5016226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "Call to vkBeginCommandBuffer() on command buffer (0x%p"
5017414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") attempts to implicitly reset cmdBuffer created from command pool (0x%" PRIxLEAST64
50184527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
5019315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            commandBuffer, HandleToUint64(cmdPool), validation_error_map[VALIDATION_ERROR_16e00064]);
50205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
50215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            resetCB(dev_data, commandBuffer);
50225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
50235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Set updated state here in case implicit reset occurs above
5024f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->state = CB_RECORDING;
5025f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->beginInfo = *pBeginInfo;
5026f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->beginInfo.pInheritanceInfo) {
5027f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->inheritanceInfo = *(cb_node->beginInfo.pInheritanceInfo);
5028f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->beginInfo.pInheritanceInfo = &cb_node->inheritanceInfo;
5029888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            // If we are a secondary command-buffer and inheriting.  Update the items we should inherit.
5030f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) &&
5031f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                (cb_node->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
50329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                cb_node->activeRenderPass = GetRenderPassState(dev_data, cb_node->beginInfo.pInheritanceInfo->renderPass);
5033f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->activeSubpass = cb_node->beginInfo.pInheritanceInfo->subpass;
5034350841afb70bf8dcfc3c6ec6b66f0aaa639553a3Tobin Ehlis                cb_node->activeFramebuffer = cb_node->beginInfo.pInheritanceInfo->framebuffer;
5035f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->framebuffers.insert(cb_node->beginInfo.pInheritanceInfo->framebuffer);
5036888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            }
50375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
50385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5039b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
50403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
50415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
50425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
50434a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.BeginCommandBuffer(commandBuffer, pBeginInfo);
5044400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
50455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
50465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
504889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL EndCommandBuffer(VkCommandBuffer commandBuffer) {
50493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
505056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5051b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
50529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
50535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
50544527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        if ((VK_COMMAND_BUFFER_LEVEL_PRIMARY == pCB->createInfo.level) ||
50554527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
5056fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // This needs spec clarification to update valid usage, see comments in PR:
5057fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/pull/516#discussion_r63013756
5058315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= insideRenderPass(dev_data, pCB, "vkEndCommandBuffer()", VALIDATION_ERROR_27400078);
5059fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop        }
50603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_END, "vkEndCommandBuffer()");
50611ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_END);
50625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto query : pCB->activeQueries) {
50633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5064315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_2740007a, "DS",
50653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Ending command buffer with in progress query: queryPool 0x%" PRIx64 ", index %d. %s",
5066315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(query.pool), query.index, validation_error_map[VALIDATION_ERROR_2740007a]);
50675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
50685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
50693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
5070b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
50710d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        auto result = dev_data->dispatch_table.EndCommandBuffer(commandBuffer);
5072b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
50735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (VK_SUCCESS == result) {
50745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->state = CB_RECORDED;
50755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
50760d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        return result;
50775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
50780d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
50795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
50805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5082bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
50833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
508456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5085b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
50869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
50875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkCommandPool cmdPool = pCB->createInfo.commandPool;
50889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, cmdPool);
5089cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes    if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
50903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5091315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_3260005c, "DS",
50923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Attempt to reset command buffer (0x%p) created from command pool (0x%" PRIxLEAST64
50933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
5094315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        commandBuffer, HandleToUint64(cmdPool), validation_error_map[VALIDATION_ERROR_3260005c]);
50955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5096315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= checkCommandBufferInFlight(dev_data, pCB, "reset", VALIDATION_ERROR_3260005a);
5097b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
50983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
50994a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandBuffer(commandBuffer, flags);
51005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5101b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
51025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        resetCB(dev_data, commandBuffer);
5103b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
51045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
51055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
51065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
510793c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
5108bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
5109bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkPipeline pipeline) {
5110e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    bool skip = false;
511156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5112b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
51139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
5114e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    if (cb_state) {
5115baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindPipeline()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
5116315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_18002415);
511729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
51181ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_state, CMD_BINDPIPELINE);
5119e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (cb_state->activeRenderPass)) {
5120e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |=
51215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
51229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pipeline), __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
5123414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "Incorrectly binding compute pipeline (0x%" PRIxLEAST64 ") during active RenderPass (0x%" PRIxLEAST64 ")",
51249b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pipeline), HandleToUint64(cb_state->activeRenderPass->renderPass));
51255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5126315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        // TODO: VALIDATION_ERROR_18000612 VALIDATION_ERROR_18000616
51275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5128e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        PIPELINE_STATE *pipe_state = getPipelineState(dev_data, pipeline);
5129e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (pipe_state) {
5130e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            cb_state->lastBound[pipelineBindPoint].pipeline_state = pipe_state;
5131e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_cb_pso_status(cb_state, pipe_state);
5132e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_pipeline_state(pipe_state);
5133daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            skip |= validate_dual_src_blend_feature(dev_data, pipe_state);
51345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
5135e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
5136315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pipeline), __LINE__, VALIDATION_ERROR_18027e01, "DS",
51379b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Attempt to bind Pipeline 0x%" PRIxLEAST64 " that doesn't exist! %s", HandleToUint64(pipeline),
5138315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_18027e01]);
5139e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        }
51409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        addCommandBufferBinding(&pipe_state->cb_bindings, {HandleToUint64(pipeline), kVulkanObjectTypePipeline}, cb_state);
5141e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
5142e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            // Add binding for child renderpass
51439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto rp_state = GetRenderPassState(dev_data, pipe_state->graphicsPipelineCI.renderPass);
5144e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            if (rp_state) {
51459b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                addCommandBufferBinding(&rp_state->cb_bindings, {HandleToUint64(rp_state->renderPass), kVulkanObjectTypeRenderPass},
51469b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        cb_state);
5147e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            }
51485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
51495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5150b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5151cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
51525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
51535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5154bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
5155bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          const VkViewport *pViewports) {
51563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
515756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5158b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
51599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
51605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
5161315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetViewport()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1e002415);
51623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()");
51631ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETVIEWPORTSTATE);
5164bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->viewportMask |= ((1u << viewportCount) - 1u) << firstViewport;
51655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5166b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
51673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
51685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
51695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5170bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
5171bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         const VkRect2D *pScissors) {
51723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
517356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5174b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
51759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
51765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
5177315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetScissor()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1d802415);
51783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()");
51791ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSCISSORSTATE);
5180bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->scissorMask |= ((1u << scissorCount) - 1u) << firstScissor;
51815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5182b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
51833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
51845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
51855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
518689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
51873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
518856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5189b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
51909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
51915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
5192315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetLineWidth()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1d602415);
51933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()");
51941ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETLINEWIDTHSTATE);
51955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_LINE_WIDTH_SET;
5196a27508babf63d50aea75883a3702979193c23683Mark Young
51974c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pPipeTrav = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline_state;
5198a27508babf63d50aea75883a3702979193c23683Mark Young        if (pPipeTrav != NULL && !isDynamic(pPipeTrav, VK_DYNAMIC_STATE_LINE_WIDTH)) {
51993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5200315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1d600626, "DS",
52013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdSetLineWidth called but pipeline was created without VK_DYNAMIC_STATE_LINE_WIDTH "
52023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "flag.  This is undefined behavior and could be ignored. %s",
5203315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1d600626]);
5204a27508babf63d50aea75883a3702979193c23683Mark Young        } else {
52059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_SET, kVulkanObjectTypeCommandBuffer, HandleToUint64(commandBuffer),
52069b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    lineWidth);
5207a27508babf63d50aea75883a3702979193c23683Mark Young        }
52085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5209b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
52103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetLineWidth(commandBuffer, lineWidth);
52115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5213bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
5214bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           float depthBiasSlopeFactor) {
52153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
521656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5217b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
52189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
52195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
5220315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetDepthBias()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1cc02415);
52213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()");
5222434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        if ((depthBiasClamp != 0.0) && (!dev_data->enabled_features.depthBiasClamp)) {
52233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5224315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1cc0062c, "DS",
52253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdSetDepthBias(): the depthBiasClamp device feature is disabled: the depthBiasClamp "
52263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "parameter must be set to 0.0. %s",
5227315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1cc0062c]);
5228434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
52293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        if (!skip) {
5230434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBIASSTATE);
5231434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            pCB->status |= CBSTATUS_DEPTH_BIAS_SET;
5232434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
52335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5234b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
52353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip)
52364a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
52375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
523989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
52403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
524156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5242b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
52439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
52445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
5245315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetBlendConstants()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1ca02415);
52463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()");
52471ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETBLENDSTATE);
52483d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        pCB->status |= CBSTATUS_BLEND_CONSTANTS_SET;
52495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5250b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
52513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetBlendConstants(commandBuffer, blendConstants);
52525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5254bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
52553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
525656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5257b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
52589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
52595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
5260315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetDepthBounds()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1ce02415);
52613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()");
52621ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBOUNDSSTATE);
52635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET;
52645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5265b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
52663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
52675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5269bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
5270bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    uint32_t compareMask) {
52713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
527256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5273b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
52749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
52755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
5276315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
5277315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilCompareMask()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1da02415);
52783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()");
52791ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREADMASKSTATE);
52805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET;
52815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5282b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
52833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
52845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5286bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
52873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
528856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5289b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
52909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
52915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
5292315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
5293315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilWriteMask()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1de02415);
52943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()");
52951ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILWRITEMASKSTATE);
52965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
52975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5298b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
52993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
53005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5302bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
53033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
530456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5305b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
53069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
53075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
5308315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
5309315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilReference()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1dc02415);
53103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()");
53111ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREFERENCESTATE);
53125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET;
53135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5314b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
53153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilReference(commandBuffer, faceMask, reference);
53165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5318bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
5319bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
5320bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
5321bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const uint32_t *pDynamicOffsets) {
5322946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
532356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5324b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5325946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
5326946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
5327baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindDescriptorSets()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
5328315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_17c02415);
5329946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()");
5330ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        // Track total count of dynamic descriptor types to make sure we have an offset for each one
5331946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t total_dynamic_descriptors = 0;
5332946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        string error_string = "";
5333946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t last_set_index = firstSet + setCount - 1;
5334946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (last_set_index >= cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size()) {
5335946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
5336946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].dynamicOffsets.resize(last_set_index + 1);
5337946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        }
5338946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        auto old_final_bound_set = cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index];
5339ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        auto pipeline_layout = getPipelineLayout(dev_data, layout);
5340ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t set_idx = 0; set_idx < setCount; set_idx++) {
5341ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cvdescriptorset::DescriptorSet *descriptor_set = GetSetNode(dev_data, pDescriptorSets[set_idx]);
5342ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (descriptor_set) {
5343946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].pipeline_layout = *pipeline_layout;
5344946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[set_idx + firstSet] = descriptor_set;
5345946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
53469b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(pDescriptorSets[set_idx]), __LINE__,
5347946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                DRAWSTATE_NONE, "DS", "Descriptor Set 0x%" PRIxLEAST64 " bound on pipeline %s",
53489b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pDescriptorSets[set_idx]), string_VkPipelineBindPoint(pipelineBindPoint));
5349ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                if (!descriptor_set->IsUpdated() && (descriptor_set->GetTotalDescriptorCount() != 0)) {
5350946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
53519b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(pDescriptorSets[set_idx]),
53529b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
5353946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "Descriptor Set 0x%" PRIxLEAST64
5354946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    " bound but it was never updated. You may want to either update it or not bind it.",
53559b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(pDescriptorSets[set_idx]));
5356ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
5357ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
535812b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                if (!verify_set_layout_compatibility(descriptor_set, pipeline_layout, set_idx + firstSet, error_string)) {
5359946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
53609b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(pDescriptorSets[set_idx]),
5361315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    __LINE__, VALIDATION_ERROR_17c002cc, "DS",
5362946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout "
5363946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "at index %u of pipelineLayout 0x%" PRIxLEAST64 " due to: %s. %s",
53649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    set_idx, set_idx + firstSet, HandleToUint64(layout), error_string.c_str(),
5365315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_17c002cc]);
53665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
5367ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
5368946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                auto set_dynamic_descriptor_count = descriptor_set->GetDynamicDescriptorCount();
5369ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
5370946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx].clear();
5371ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
5372946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (set_dynamic_descriptor_count) {
5373ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    // First make sure we won't overstep bounds of pDynamicOffsets array
5374946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if ((total_dynamic_descriptors + set_dynamic_descriptor_count) > dynamicOffsetCount) {
53759b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        skip |= log_msg(
53769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
53779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pDescriptorSets[set_idx]), __LINE__, DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
53789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "descriptorSet #%u (0x%" PRIxLEAST64
53799b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
53809b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "array. There must be one dynamic offset for each dynamic descriptor being bound.",
53819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            set_idx, HandleToUint64(pDescriptorSets[set_idx]), descriptor_set->GetDynamicDescriptorCount(),
53829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            (dynamicOffsetCount - total_dynamic_descriptors));
5383ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    } else {  // Validate and store dynamic offsets with the set
5384ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Validate Dynamic Offset Minimums
5385946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        uint32_t cur_dyn_offset = total_dynamic_descriptors;
5386ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        for (uint32_t d = 0; d < descriptor_set->GetTotalDescriptorCount(); d++) {
5387ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
538816769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                                if (SafeModulo(
5389ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
5390ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
5391315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    skip |=
5392315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
5393315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
5394315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VALIDATION_ERROR_17c002d4, "DS",
5395315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
5396315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
5397315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
5398315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
5399315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                validation_error_map[VALIDATION_ERROR_17c002d4]);
5400ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
5401ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
5402ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            } else if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
540316769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                                if (SafeModulo(
5404ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
5405ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
5406315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    skip |=
5407315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
5408315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
5409315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VALIDATION_ERROR_17c002d4, "DS",
5410315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
5411315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
5412315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
5413315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment,
5414315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                validation_error_map[VALIDATION_ERROR_17c002d4]);
5415ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
5416ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
5417ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            }
541872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        }
5419ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
5420946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx] =
5421946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            std::vector<uint32_t>(pDynamicOffsets + total_dynamic_descriptors,
5422946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                  pDynamicOffsets + total_dynamic_descriptors + set_dynamic_descriptor_count);
5423ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Keep running total of dynamic descriptor count to verify at the end
5424946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        total_dynamic_descriptors += set_dynamic_descriptor_count;
542572d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    }
542672d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                }
5427ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            } else {
54289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |=
54299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
54309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pDescriptorSets[set_idx]), __LINE__, DRAWSTATE_INVALID_SET, "DS",
54319b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Attempt to bind descriptor set 0x%" PRIxLEAST64 " that doesn't exist!",
54329b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pDescriptorSets[set_idx]));
5433ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            }
5434946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            UpdateCmdBufferLastCmd(cb_state, CMD_BINDDESCRIPTORSETS);
5435ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update
5436ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (firstSet > 0) {  // Check set #s below the first bound set
5437ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                for (uint32_t i = 0; i < firstSet; ++i) {
5438946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if (cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] &&
543912b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                        !verify_set_layout_compatibility(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i],
5440946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                         pipeline_layout, i, error_string)) {
5441946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        skip |= log_msg(
5442ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
5443ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
54449b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i]), __LINE__, DRAWSTATE_NONE,
54459b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "DS", "DescriptorSet 0x%" PRIxLEAST64
54469b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                  " previously bound as set #%u was disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
54479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i]), i,
54489b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(layout));
5449946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE;
54505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
54515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
54525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
5453ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // Check if newly last bound set invalidates any remaining bound sets
5454946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            if ((cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (last_set_index)) {
5455946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (old_final_bound_set &&
545612b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                    !verify_set_layout_compatibility(old_final_bound_set, pipeline_layout, last_set_index, error_string)) {
5457946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    auto old_set = old_final_bound_set->GetSet();
5458946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
54599b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(old_set), __LINE__,
5460946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    DRAWSTATE_NONE, "DS", "DescriptorSet 0x%" PRIxLEAST64
5461946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " previously bound as set #%u is incompatible with set 0x%" PRIxLEAST64
5462946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " newly bound as set #%u so set #%u and any subsequent sets were "
5463946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          "disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
54649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(old_set), last_set_index,
54659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index]),
54669b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    last_set_index, last_set_index + 1, HandleToUint64(layout));
5467946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
5468ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
5469787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            }
5470ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
5471ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
5472946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (total_dynamic_descriptors != dynamicOffsetCount) {
5473315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |=
5474315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5475315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_17c002ce, "DS",
5476315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
5477315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "is %u. It should exactly match the number of dynamic descriptors. %s",
5478315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        setCount, total_dynamic_descriptors, dynamicOffsetCount, validation_error_map[VALIDATION_ERROR_17c002ce]);
54795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
54805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5481b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5482946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
54834a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
54844a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                       pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
54855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5487bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
5488bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkIndexType indexType) {
5489946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
549056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5491593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that IBs have correct usage state flagged
5492b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5493b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
54949a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
54959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
54965cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && buffer_state) {
5497315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
5498315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBindIndexBuffer()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_17e02415);
5499946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
5500315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindIndexBuffer()", VALIDATION_ERROR_17e00364);
5501ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        std::function<bool()> function = [=]() {
5502ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindIndexBuffer()");
5503ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        };
5504ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->validate_functions.push_back(function);
5505ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDINDEXBUFFER);
5506ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        VkDeviceSize offset_align = 0;
5507ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        switch (indexType) {
5508ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT16:
5509ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 2;
5510ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
5511ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT32:
5512ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 4;
5513ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
5514ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            default:
5515ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0
5516ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
55175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5518ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        if (!offset_align || (offset % offset_align)) {
5519df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
55209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(commandBuffer), __LINE__, DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS",
5521946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") does not fall on alignment (%s) boundary.", offset,
5522946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            string_VkIndexType(indexType));
5523ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
5524ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->status |= CBSTATUS_INDEX_BUFFER_BOUND;
5525ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
5526ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
55275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5528b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5529946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
55305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
55325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisvoid updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) {
55335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t end = firstBinding + bindingCount;
55345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->currentDrawData.buffers.size() < end) {
55355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.resize(end);
55365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
55375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bindingCount; ++i) {
55385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i];
55395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
55405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5542e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic inline void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); }
55435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5544bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
5545bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
5546946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
554756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5548593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that VBs have correct usage state flagged
5549b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5550b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
55519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
55529f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    if (cb_node) {
5553315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
5554315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBindVertexBuffers()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_18202415);
5555baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffers()");
5556ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t i = 0; i < bindingCount; ++i) {
5557ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            auto buffer_state = GetBufferState(dev_data, pBuffers[i]);
5558ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            assert(buffer_state);
5559315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindVertexBuffers()", VALIDATION_ERROR_182004e8);
5560ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            std::function<bool()> function = [=]() {
5561ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindVertexBuffers()");
5562ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            };
5563ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cb_node->validate_functions.push_back(function);
55645fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour            if (pOffsets[i] >= buffer_state->createInfo.size) {
55655fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5566315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(buffer_state->buffer), __LINE__, VALIDATION_ERROR_182004e4, "DS",
55675fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour                                "vkCmdBindVertexBuffers() offset (0x%" PRIxLEAST64 ") is beyond the end of the buffer. %s",
5568315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                pOffsets[i], validation_error_map[VALIDATION_ERROR_182004e4]);
55695fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour            }
55705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5571ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDVERTEXBUFFER);
5572ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        updateResourceTracking(cb_node, firstBinding, bindingCount, pBuffers);
55735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
55747828015969ab31ee01d597f0288cbb124b637fcdMark Lobodzinski        assert(0);
55755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5576b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5577946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
55785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
558025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Expects global_lock to be held by caller
55815569d6457ac22e7d245f3cdee045e71ffbc8b06eTobin Ehlisstatic void MarkStoreImagesAndBuffersAsWritten(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
55827a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto imageView : pCB->updateImages) {
55839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, imageView);
5584cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!view_state) continue;
5585249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
55869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, view_state->create_info.image);
55871facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        assert(image_state);
5588e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
55891facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, image_state, true);
5590e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
55917a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
55927a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
55937a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    }
55947a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto buffer : pCB->updateBuffers) {
55959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, buffer);
55965cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        assert(buffer_state);
5597e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
55985cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, buffer_state, true);
5599e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
56007a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
56017a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
56025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
56035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5605ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle validation for all CmdDraw* type functions
5606ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool ValidateCmdDrawType(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
5607baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                CMD_TYPE cmd_type, GLOBAL_CB_NODE **cb_state, const char *caller, VkQueueFlags queue_flags,
5608baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                UNIQUE_VALIDATION_ERROR_CODE queue_flag_code, UNIQUE_VALIDATION_ERROR_CODE msg_code,
5609baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                UNIQUE_VALIDATION_ERROR_CODE const dynamic_state_msg_code) {
561058b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    bool skip = false;
56119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cb_state = GetCBNode(dev_data, cmd_buffer);
561258b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (*cb_state) {
5613baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, *cb_state, caller, queue_flags, queue_flag_code);
5614ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        skip |= ValidateCmd(dev_data, *cb_state, cmd_type, caller);
56154f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        skip |= ValidateDrawState(dev_data, *cb_state, indexed, bind_point, caller, dynamic_state_msg_code);
561625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        skip |= (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) ? outsideRenderPass(dev_data, *cb_state, caller, msg_code)
561725d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis                                                                : insideRenderPass(dev_data, *cb_state, caller, msg_code);
561858b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
561958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    return skip;
562058b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis}
562158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis
562225d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis// Generic function to handle state update for all CmdDraw* and CmdDispatch* type functions
5623ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawDispatchType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
5624ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           CMD_TYPE cmd_type) {
5625ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateDrawState(dev_data, cb_state, bind_point);
56262f921d33544c162dcb726fc3c7b915e89c02ff24Tobin Ehlis    MarkStoreImagesAndBuffersAsWritten(dev_data, cb_state);
56271ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis    UpdateCmdBufferLastCmd(cb_state, cmd_type);
562825d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
562925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
5630ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle state update for all CmdDraw* type functions
5631ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
5632b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes                                   CMD_TYPE cmd_type) {
5633ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, cmd_type);
5634c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    updateResourceTrackingOnDraw(cb_state);
5635b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    cb_state->hasDrawCmd = true;
5636ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
5637ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
5638ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDraw(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
5639ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   GLOBAL_CB_NODE **cb_state, const char *caller) {
5640baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAW, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
5641315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               VALIDATION_ERROR_1a202415, VALIDATION_ERROR_1a200017, VALIDATION_ERROR_1a200376);
5642ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
5643ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
5644ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDraw(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
5645b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAW);
5646c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis}
5647c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis
564889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
564989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                   uint32_t firstVertex, uint32_t firstInstance) {
565056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
565158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
5652b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5653ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = PreCallValidateCmdDraw(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state, "vkCmdDraw()");
5654b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
565558b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (!skip) {
56564a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
5657c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.lock();
5658ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDraw(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
5659c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.unlock();
5660c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    }
56615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5663ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexed(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
5664ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
5665baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXED, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
5666315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               VALIDATION_ERROR_1a402415, VALIDATION_ERROR_1a400017, VALIDATION_ERROR_1a40039c);
5667ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
5668ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
5669ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexed(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
5670b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXED);
5671ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
5672ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
5673bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
5674bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
567556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5676ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
5677b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5678ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexed(dev_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
5679ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              "vkCmdDrawIndexed()");
5680b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5681ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    if (!skip) {
56824a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
5683ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.lock();
5684ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexed(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
5685ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.unlock();
5686ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    }
56875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5689ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
5690ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
5691ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           const char *caller) {
5692315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    bool skip =
5693315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDIRECT, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
5694315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            VALIDATION_ERROR_1aa02415, VALIDATION_ERROR_1aa00017, VALIDATION_ERROR_1aa003cc);
56959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
5696315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_1aa003b4);
569713c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
569813c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // VkDrawIndirectCommand structures accessed by this command must be 0, which will require access to the contents of 'buffer'.
5699d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    return skip;
5700d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
5701d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
5702ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
5703ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          BUFFER_STATE *buffer_state) {
5704b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDIRECT);
5705d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
5706d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
5707d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
5708bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
5709bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           uint32_t stride) {
571056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5711d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
5712d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
5713b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5714872a2f0ca3ffdeddfa7483e777191fa64b853892Tony Barbour    bool skip = PreCallValidateCmdDrawIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
5715ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               &buffer_state, "vkCmdDrawIndirect()");
5716b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5717d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    if (!skip) {
57184a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
5719d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.lock();
5720ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
5721d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.unlock();
5722d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    }
57235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5725ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexedIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
5726ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
5727ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  BUFFER_STATE **buffer_state, const char *caller) {
5728315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    bool skip =
5729315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXEDINDIRECT, cb_state, caller,
5730315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1a602415, VALIDATION_ERROR_1a600017, VALIDATION_ERROR_1a600434);
57319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
5732315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_1a60041c);
573313c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
573413c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // VkDrawIndexedIndirectCommand structures accessed by this command must be 0, which will require access to the contents of
573513c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // 'buffer'.
57360c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    return skip;
57370c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
57380c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
5739ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexedIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
5740ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                 BUFFER_STATE *buffer_state) {
5741b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXEDINDIRECT);
57420c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
57430c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
57440c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
5745bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
5746bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  uint32_t count, uint32_t stride) {
574756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
57480c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
57490c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
5750b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
57510c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexedIndirect(dev_data, commandBuffer, buffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS,
5752ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                      &cb_state, &buffer_state, "vkCmdDrawIndexedIndirect()");
5753b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
57540c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    if (!skip) {
57554a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
57560c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.lock();
5757ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexedIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
57580c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.unlock();
57590c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    }
57605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5762ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatch(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
5763ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                       VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
5764baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCH, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
5765315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               VALIDATION_ERROR_19c02415, VALIDATION_ERROR_19c00017, VALIDATION_ERROR_UNDEFINED);
576625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
576725d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
5768ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatch(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
5769ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCH);
577025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
577125d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
577289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
577356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
577425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
5775b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5776ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip =
5777ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PreCallValidateCmdDispatch(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_COMPUTE, &cb_state, "vkCmdDispatch()");
5778b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
577925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    if (!skip) {
57804a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatch(commandBuffer, x, y, z);
578125d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.lock();
5782ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatch(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
578325d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.unlock();
578425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    }
57855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5787ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatchIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
5788ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
5789ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               BUFFER_STATE **buffer_state, const char *caller) {
5790baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    bool skip =
5791baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCHINDIRECT, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
5792315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            VALIDATION_ERROR_1a002415, VALIDATION_ERROR_1a000017, VALIDATION_ERROR_UNDEFINED);
57939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
5794315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_1a000322);
579579c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    return skip;
579679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
579779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
5798ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatchIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
5799ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              BUFFER_STATE *buffer_state) {
5800ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCHINDIRECT);
580179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
580279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
580379c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
5804bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
580556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
580679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
580779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
5808b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
58097433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis    bool skip = PreCallValidateCmdDispatchIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_COMPUTE,
5810ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                   &cb_state, &buffer_state, "vkCmdDispatchIndirect()");
5811b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
581279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    if (!skip) {
58134a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatchIndirect(commandBuffer, buffer, offset);
581479c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.lock();
5815ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatchIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, buffer_state);
581679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.unlock();
581779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    }
58185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
582089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
582189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                         uint32_t regionCount, const VkBufferCopy *pRegions) {
5822c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5823b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5824ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
5825c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
5826c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
5827c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
5828593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
5829c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    if (cb_node && src_buffer_state && dst_buffer_state) {
5830c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        bool skip = PreCallValidateCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
5831c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        if (!skip) {
5832c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            PreCallRecordCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
5833c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            lock.unlock();
5834c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            device_data->dispatch_table.CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
5835c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        }
5836ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
5837c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        lock.unlock();
5838ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
58395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5842bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
5843bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
5844bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageCopy *pRegions) {
58456a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    bool skip = false;
58466a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5847b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5848249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
58496a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
58506a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
58516a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
58521facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && src_image_state && dst_image_state) {
58536a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        skip = PreCallValidateCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions,
58546a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                           srcImageLayout, dstImageLayout);
58556a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        if (!skip) {
5856a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis            PreCallRecordCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, srcImageLayout,
5857a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                      dstImageLayout);
58586a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            lock.unlock();
58596a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            device_data->dispatch_table.CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
58606a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                                     pRegions);
58615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5862249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
58636a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        lock.unlock();
5864249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
58655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5868eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski// Validate that an image's sampleCount matches the requirement for a specific API call
586960568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageSampleCount(layer_data *dev_data, IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count,
587060568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinski                              const char *location, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
5871eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    bool skip = false;
58721facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state->createInfo.samples != sample_count) {
58739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
58749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(image_state->image), 0, msgCode, "DS",
58759b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       "%s for image 0x%" PRIxLEAST64 " was created with a sample count of %s but must be %s. %s", location,
58769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(image_state->image), string_VkSampleCountFlagBits(image_state->createInfo.samples),
58779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       string_VkSampleCountFlagBits(sample_count), validation_error_map[msgCode]);
5878eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    }
5879eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    return skip;
5880eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski}
5881eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski
5882bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
5883bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
5884bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageBlit *pRegions, VkFilter filter) {
588556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5886b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5887593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
58889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
58899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
58909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
58910dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
5892055112ec99304db71d55b69a60e1da14e8af8f60Mark Lobodzinski    bool skip = PreCallValidateCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, filter);
58930dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
5894dca02371c9531e7a9a2a51decae1db4d297862c4Mark Lobodzinski    if (!skip) {
5895eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        PreCallRecordCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state);
5896eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        lock.unlock();
58974a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
58984a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                              pRegions, filter);
58990dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski    }
59005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5902bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
5903bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkImageLayout dstImageLayout, uint32_t regionCount,
5904bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBufferImageCopy *pRegions) {
5905940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5906b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5907940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
5908940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
5909940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
5910940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
5911940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_buffer_state && dst_image_state) {
5912940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyBufferToImage(device_data, dstImageLayout, cb_node, src_buffer_state, dst_image_state,
591371c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyBufferToImage()");
5914ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
5915d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
5916ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
5917e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01244 here, or put in object tracker?
59185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5919940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
5920a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis        PreCallRecordCmdCopyBufferToImage(device_data, cb_node, src_buffer_state, dst_image_state, regionCount, pRegions,
5921a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                          dstImageLayout);
5922d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
5923940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
5924d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
59255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5927bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
5928bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
5929940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
5930940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5931b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5932593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
5933940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
5934940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
5935940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
5936940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_image_state && dst_buffer_state) {
5937940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyImageToBuffer(device_data, srcImageLayout, cb_node, src_image_state, dst_buffer_state,
593871c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyImageToBuffer()");
5939ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
5940d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
5941ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
5942e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01262 here, or put in object tracker?
59435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5944940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
5945a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis        PreCallRecordCmdCopyImageToBuffer(device_data, cb_node, src_image_state, dst_buffer_state, regionCount, pRegions,
5946a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                          srcImageLayout);
5947d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
5948940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
5949d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
59505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5952bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
5953bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkDeviceSize dataSize, const uint32_t *pData) {
59543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
595556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5956b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5957593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
59589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
59599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
59605cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
5961315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdUpdateBuffer()", VALIDATION_ERROR_1e400046);
5962ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
59635cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
5964ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
5965315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
5966315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                         VALIDATION_ERROR_1e400044, "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
5967e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
59685cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
5969e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
59705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
59719f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
5972593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
5973315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
5974315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdUpdateBuffer()",
5975315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_1e402415);
59763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()");
59771ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_node, CMD_UPDATEBUFFER);
5978315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, cb_node, "vkCmdUpdateBuffer()", VALIDATION_ERROR_1e400017);
5979ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
5980ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
59815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5982b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
59833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
59845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5986bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
5987bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         VkDeviceSize size, uint32_t data) {
598823bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
5989b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
599023bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
599123bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto buffer_state = GetBufferState(device_data, dstBuffer);
5992593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
599323bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    if (cb_node && buffer_state) {
599423bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        bool skip = PreCallValidateCmdFillBuffer(device_data, cb_node, buffer_state);
599523bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        if (!skip) {
599623bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            PreCallRecordCmdFillBuffer(device_data, cb_node, buffer_state);
599723bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            lock.unlock();
599823bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            device_data->dispatch_table.CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
599923bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        }
6000ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
600123bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        lock.unlock();
6002ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
60035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60064028af23e688ab5730f48ab2244dd042e2eefaedMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
60074028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearAttachment *pAttachments, uint32_t rectCount,
60084028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearRect *pRects) {
60094028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    bool skip = false;
601056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
60114028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    {
60124028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
60134028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        skip = PreCallValidateCmdClearAttachments(dev_data, commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
60144028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    }
6015cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
60165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60180482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
60190482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkClearColorValue *pColor, uint32_t rangeCount,
60200482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkImageSubresourceRange *pRanges) {
602156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6022b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
60230482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
60240482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearColorImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
60250482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
60260482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARCOLORIMAGE);
60270482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
60280482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
60290482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    }
60300482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski}
60310482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
60320482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
60330482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
60340482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkImageSubresourceRange *pRanges) {
603556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
60360482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
60370482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
60380482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearDepthStencilImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
60390482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
60400482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARDEPTHSTENCILIMAGE);
60410482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
60420482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
60437f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    }
60445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6046bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
6047bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
6048bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkImageResolve *pRegions) {
604956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6050b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6051593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
60529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
60539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
60549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
605509fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
605625f7873c9ce3ed39d18bba8750d7538905e150dfMark Lobodzinski    bool skip = PreCallValidateCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions);
605709fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
605809fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    if (!skip) {
60596c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        PreCallRecordCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state);
60606c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        lock.unlock();
60614a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
60624a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                 pRegions);
606309fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    }
60645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6066a8d1e377bdeaf61a3209cb997502da4356a185bbMike WeiblenVKAPI_ATTR void VKAPI_CALL GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
6067a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen                                                     VkSubresourceLayout *pLayout) {
6068a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6069a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen
6070a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    bool skip = PreCallValidateGetImageSubresourceLayout(device_data, image, pSubresource);
6071a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    if (!skip) {
6072b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        device_data->dispatch_table.GetImageSubresourceLayout(device, image, pSubresource, pLayout);
6073b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    }
6074b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski}
6075b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski
6076b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentinebool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
607756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
60789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
6079b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (pCB) {
6080b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventToStageMap[event] = stageMask;
6081b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
6082b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    auto queue_data = dev_data->queueMap.find(queue);
6083b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (queue_data != dev_data->queueMap.end()) {
6084b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        queue_data->second.eventToStageMap[event] = stageMask;
6085b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
6086b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return false;
6087b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
6088b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
6089bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
60903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
609156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6092b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
60939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
60945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
60953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6096315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1d402415);
60973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()");
60981ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETEVENT);
6099315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent()", VALIDATION_ERROR_1d400017);
6100315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdSetEvent()", VALIDATION_ERROR_1d4008fc,
6101315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1d4008fe);
61029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
61034710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
61049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            addCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(event), kVulkanObjectTypeEvent}, pCB);
61054710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
6106ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
61075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
6108c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
6109c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
6110c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
6111f49bd2b5f4c968a3033b3e5099bbbcff51201575Chris Forbes        pCB->eventUpdates.emplace_back([=](VkQueue q){return setEventStageMask(q, commandBuffer, event, stageMask);});
61125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6113b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
61143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetEvent(commandBuffer, event, stageMask);
61155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6117bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
61183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
611956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6120b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
61219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
61225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
61233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdResetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6124315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1c402415);
61253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()");
61261ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_RESETEVENT);
6127315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent()", VALIDATION_ERROR_1c400017);
6128315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdResetEvent()", VALIDATION_ERROR_1c400904,
6129315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1c400906);
61309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
61314710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
61329b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            addCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(event), kVulkanObjectTypeEvent}, pCB);
61334710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
6134ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
61355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
6136c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
6137c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
6138c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
6139315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        // TODO : Add check for VALIDATION_ERROR_32c008f8
6140f49bd2b5f4c968a3033b3e5099bbbcff51201575Chris Forbes        pCB->eventUpdates.emplace_back([=](VkQueue q){return setEventStageMask(q, commandBuffer, event, VkPipelineStageFlags(0));});
61415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6142b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
61433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdResetEvent(commandBuffer, event, stageMask);
61445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6146e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
6147e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
6148e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
6149e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkImageMemoryBarrier *pImageMemBarriers) {
6150a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    bool skip = false;
615156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(cmdBuffer), layer_data_map);
61529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, cmdBuffer);
61535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass && memBarrierCount) {
6154ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        if (!pCB->activeRenderPass->hasSelfDependency[pCB->activeSubpass]) {
6155df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
61569b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
6157cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Barriers cannot be set during subpass %d "
6158cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "with no self dependency specified.",
6159a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, pCB->activeSubpass);
61605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
61615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
61635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pImageMemBarriers[i];
61648f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        auto image_data = GetImageState(dev_data, mem_barrier->image);
61658f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (image_data) {
61668f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex;
61678f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex;
61688f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            if (image_data->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
61698f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // srcQueueFamilyIndex and dstQueueFamilyIndex must both
61708f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // be VK_QUEUE_FAMILY_IGNORED
61718f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) {
61728f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
61739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
61749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image Barrier for image 0x%" PRIx64
61759b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         " was created with sharingMode of "
61769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "VK_SHARING_MODE_CONCURRENT. Src and dst "
61779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.",
61789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    funcName, HandleToUint64(mem_barrier->image));
61798f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                }
61808f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            } else {
61818f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and
61828f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED,
61838f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // or both be a valid queue family
61848f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) &&
61858f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    (src_q_f_index != dst_q_f_index)) {
61868f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
61879b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
61889b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64
61899b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         " was created with sharingMode "
61909b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or "
61919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both "
61929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "must be.",
61939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    funcName, HandleToUint64(mem_barrier->image));
61948f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) &&
61958f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                           ((src_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
61968f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                            (dst_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()))) {
61978f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
61989b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
61998f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
62008f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    "%s: Image 0x%" PRIx64
62018f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    " was created with sharingMode "
62028f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d"
62038f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER
62048f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    "queueFamilies crated for this device.",
62059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    funcName, HandleToUint64(mem_barrier->image), src_q_f_index, dst_q_f_index,
62068f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    dev_data->phys_dev_properties.queue_family_properties.size());
62075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
62085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
62098f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        }
62105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62118f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (mem_barrier->oldLayout != mem_barrier->newLayout) {
62128f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            if (pCB->activeRenderPass) {
62139b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |=
62149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6215315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(cmdBuffer), __LINE__, VALIDATION_ERROR_1b80093a, "DS",
62169b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "%s: As the Image Barrier for image 0x%" PRIx64
62179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            " is being executed within a render pass instance, oldLayout must equal newLayout yet they are "
62189b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "%s and %s. %s",
62199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            funcName, HandleToUint64(mem_barrier->image), string_VkImageLayout(mem_barrier->oldLayout),
6220315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            string_VkImageLayout(mem_barrier->newLayout), validation_error_map[VALIDATION_ERROR_1b80093a]);
6221d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            }
62228f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            skip |= ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source");
62238f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            skip |= ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest");
62248f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        }
62258f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
62268f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
62279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
6228df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Image Layout cannot be transitioned to UNDEFINED or "
6229df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "PREINITIALIZED.",
6230df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            funcName);
62318f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        }
62328f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (image_data) {
62338f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            auto aspect_mask = mem_barrier->subresourceRange.aspectMask;
62342044b110851e8f1b75d6d406a0c88612476c63dbChris Forbes            skip |= ValidateImageAspectMask(dev_data, image_data->image, image_data->createInfo.format, aspect_mask, funcName);
623595b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski
623623c5a2092f724fef497a5c87a489f32c8fa51e58Petr Kraus            std::string param_name = "pImageMemoryBarriers[" + std::to_string(i) + "].subresourceRange";
6237dab32891b91206a5bef7a3929b781e44fc1b7268Petr Kraus            skip |= ValidateImageSubresourceRange(dev_data, image_data, false, mem_barrier->subresourceRange, funcName,
623823c5a2092f724fef497a5c87a489f32c8fa51e58Petr Kraus                                                  param_name.c_str());
62395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
62405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62412044b110851e8f1b75d6d406a0c88612476c63dbChris Forbes
62425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
62435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pBufferMemBarriers[i];
62445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->activeRenderPass) {
6245df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
62469b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
6247df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Buffer Barriers cannot be used during a render pass.", funcName);
62485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!mem_barrier) continue;
62505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate buffer barrier queue family indices
62525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
6253b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->srcQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
62545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
6255b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->dstQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size())) {
6256df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
62579b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
6258cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64
6259cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            " has QueueFamilyIndex greater "
6260a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.",
62619b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            funcName, HandleToUint64(mem_barrier->buffer),
6262a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            dev_data->phys_dev_properties.queue_family_properties.size());
62635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
62645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, mem_barrier->buffer);
62665cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        if (buffer_state) {
62675cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            auto buffer_size = buffer_state->requirements.size;
62685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->offset >= buffer_size) {
62699b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
62709b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
62719b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64
62729b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                 " which is not less than total size 0x%" PRIx64 ".",
62739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                funcName, HandleToUint64(mem_barrier->buffer), HandleToUint64(mem_barrier->offset),
62749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(buffer_size));
6275df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
6276df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip |=
6277df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
62789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
6279df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " and size 0x%" PRIx64
6280df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            " whose sum is greater than total size 0x%" PRIx64 ".",
62819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            funcName, HandleToUint64(mem_barrier->buffer), HandleToUint64(mem_barrier->offset),
62829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem_barrier->size), HandleToUint64(buffer_size));
62835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
62845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
62855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6286a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    return skip;
62875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6289bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool validateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex,
6290bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            VkPipelineStageFlags sourceStageMask) {
62913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
6292b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    VkPipelineStageFlags stageMask = 0;
629356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
6294b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    for (uint32_t i = 0; i < eventCount; ++i) {
62952ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event = pCB->events[firstEventIndex + i];
6296b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        auto queue_data = dev_data->queueMap.find(queue);
6297cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (queue_data == dev_data->queueMap.end()) return false;
62982ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event_data = queue_data->second.eventToStageMap.find(event);
6299b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        if (event_data != queue_data->second.eventToStageMap.end()) {
6300b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            stageMask |= event_data->second;
6301b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        } else {
63029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto global_event_data = GetEventNode(dev_data, event);
63039556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis            if (!global_event_data) {
63043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
63059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
63069b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Event 0x%" PRIx64 " cannot be waited on if it has never been set.", HandleToUint64(event));
6307b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            } else {
63089556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis                stageMask |= global_event_data->stageMask;
6309b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            }
6310b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        }
6311b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
6312c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // TODO: Need to validate that host_bit is only set if set event is called
6313c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // but set event can be called at any time.
6314c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    if (sourceStageMask != stageMask && sourceStageMask != (stageMask | VK_PIPELINE_STAGE_HOST_BIT)) {
63153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6316315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_1e62d401, "DS",
63173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Submitting cmdbuffer with call to VkCmdWaitEvents "
63183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "using srcStageMask 0x%X which must be the bitwise "
63193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "OR of the stageMask parameters used in calls to "
63203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if "
63213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "used with vkSetEvent but instead is 0x%X. %s",
6322315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        sourceStageMask, stageMask, validation_error_map[VALIDATION_ERROR_1e62d401]);
6323b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
63243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
6325b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
6326b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
632707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski// Note that we only check bits that HAVE required queueflags -- don't care entries are skipped
632807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic std::unordered_map<VkPipelineStageFlags, VkQueueFlags> supported_pipeline_stages_table = {
632907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
633007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
633107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
633207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
633307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
633407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
633507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
633607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
633707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
633807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
633907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
634007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_QUEUE_COMPUTE_BIT},
634107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT},
634207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_QUEUE_GRAPHICS_BIT}};
634307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
634407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic const VkPipelineStageFlags stage_flag_bit_array[] = {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX,
634507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
634607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
634707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
634807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
634907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
635007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
635107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
635207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
635307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
635407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
635507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
635607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TRANSFER_BIT,
635707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT};
635807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
635907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool CheckStageMaskQueueCompatibility(layer_data *dev_data, VkCommandBuffer command_buffer, VkPipelineStageFlags stage_mask,
636007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      VkQueueFlags queue_flags, const char *function, const char *src_or_dest,
636107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      UNIQUE_VALIDATION_ERROR_CODE error_code) {
636207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
636307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Lookup each bit in the stagemask and check for overlap between its table bits and queue_flags
636407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    for (const auto &item : stage_flag_bit_array) {
636507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if (stage_mask & item) {
636607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            if ((supported_pipeline_stages_table[item] & queue_flags) == 0) {
636707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                skip |=
636807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
63699b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(command_buffer), __LINE__, error_code, "DL",
637007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "%s(): %s flag %s is not compatible with the queue family properties of this "
637107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "command buffer. %s",
637207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            function, src_or_dest, string_VkPipelineStageFlagBits(static_cast<VkPipelineStageFlagBits>(item)),
637307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            validation_error_map[error_code]);
637407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            }
637507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
637607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
637707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
637807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
637907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
638007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool ValidateStageMasksAgainstQueueCapabilities(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
638107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                VkPipelineStageFlags source_stage_mask, VkPipelineStageFlags dest_stage_mask,
638207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                const char *function, UNIQUE_VALIDATION_ERROR_CODE error_code) {
638307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
638407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    uint32_t queue_family_index = dev_data->commandPoolMap[cb_state->createInfo.commandPool].queueFamilyIndex;
638556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(dev_data->physical_device), instance_layer_data_map);
63869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, dev_data->physical_device);
638707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
638807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Any pipeline stage included in srcStageMask or dstStageMask must be supported by the capabilities of the queue family
638907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // specified by the queueFamilyIndex member of the VkCommandPoolCreateInfo structure that was used to create the VkCommandPool
639007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // that commandBuffer was allocated from, as specified in the table of supported pipeline stages.
639107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
639207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    if (queue_family_index < physical_device_state->queue_family_properties.size()) {
639307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        VkQueueFlags specified_queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
639407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
639507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((source_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
639607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, source_stage_mask, specified_queue_flags,
639707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "srcStageMask", error_code);
639807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
639907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((dest_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
640007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, dest_stage_mask, specified_queue_flags,
640107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "dstStageMask", error_code);
640207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
640307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
640407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
640507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
640607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
6407d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
6408d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
6409d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
6410d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
6411d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
6412d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
641356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6414b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
64159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
6416d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
6417d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= ValidateStageMasksAgainstQueueCapabilities(dev_data, cb_state, sourceStageMask, dstStageMask, "vkCmdWaitEvents",
6418315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                           VALIDATION_ERROR_1e600918);
6419315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, sourceStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_1e60090e,
6420315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1e600912);
6421315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, dstStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_1e600910,
6422315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1e600914);
6423d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        auto first_event_index = cb_state->events.size();
64245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < eventCount; ++i) {
64259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto event_state = GetEventNode(dev_data, pEvents[i]);
64264710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            if (event_state) {
64279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                addCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(pEvents[i]), kVulkanObjectTypeEvent}, cb_state);
6428d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                event_state->cb_bindings.insert(cb_state);
6429ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis            }
6430d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->waitedEvents.insert(pEvents[i]);
6431d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->events.push_back(pEvents[i]);
64325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6433f49bd2b5f4c968a3033b3e5099bbbcff51201575Chris Forbes        cb_state->eventUpdates.emplace_back([=](VkQueue q){
6434f49bd2b5f4c968a3033b3e5099bbbcff51201575Chris Forbes            return validateEventStageMask(q, cb_state, eventCount, first_event_index, sourceStageMask);
6435f49bd2b5f4c968a3033b3e5099bbbcff51201575Chris Forbes        });
6436baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWaitEvents()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6437315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1e602415);
6438ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WAITEVENTS, "vkCmdWaitEvents()");
6439ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WAITEVENTS);
6440a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen        skip |=
6441a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen            ValidateBarriersToImages(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers, "vkCmdWaitEvents()");
6442e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        if (!skip) {
6443e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski            TransitionImageLayouts(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
6444e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        }
6445e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski
6446364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= ValidateBarriers("vkCmdWaitEvents()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
6447d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
64485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6449b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6450d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (!skip)
64514a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
64524a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
64534a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               imageMemoryBarrierCount, pImageMemoryBarriers);
64545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
645603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinskistatic bool PreCallValidateCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
645703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
645803122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
645903122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
646003122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
646103122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    bool skip = false;
646203122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMasksAgainstQueueCapabilities(device_data, cb_state, srcStageMask, dstStageMask, "vkCmdPipelineBarrier",
6463315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                       VALIDATION_ERROR_1b80093e);
6464baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    skip |= ValidateCmdQueueFlags(device_data, cb_state, "vkCmdPipelineBarrier()",
6465315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_1b802415);
646603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateCmd(device_data, cb_state, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()");
6467315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateStageMaskGsTsEnables(device_data, srcStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_1b800920,
6468315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                         VALIDATION_ERROR_1b800924);
6469315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateStageMaskGsTsEnables(device_data, dstStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_1b800922,
6470315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                         VALIDATION_ERROR_1b800926);
6471a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen    skip |= ValidateBarriersToImages(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers,
6472a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen                                     "vkCmdPipelineBarrier()");
647303122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateBarriers("vkCmdPipelineBarrier()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
647403122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                             pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
647503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    return skip;
647603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski}
647703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski
64786f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinskistatic void PreCallRecordCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
64796f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski                                            uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
64806f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    UpdateCmdBufferLastCmd(cb_state, CMD_PIPELINEBARRIER);
64816f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    TransitionImageLayouts(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
64826f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski}
64836f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski
6484d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
6485d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
6486d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
6487d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
6488d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
6489d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
64906f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6491b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
64926f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(device_data, commandBuffer);
6493d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
64946f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        skip |= PreCallValidateCmdPipelineBarrier(device_data, cb_state, commandBuffer, srcStageMask, dstStageMask,
649503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
649603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
64976f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        if (!skip) {
64986f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski            PreCallRecordCmdPipelineBarrier(device_data, cb_state, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
64996f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        }
65006f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    } else {
65016f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        assert(0);
65025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6503b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6504a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour    if (!skip) {
6505a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour        device_data->dispatch_table.CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount,
6506a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour                                                       pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
6507a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour                                                       imageMemoryBarrierCount, pImageMemoryBarriers);
6508a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour    }
65095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
651143ec3f090ca979777b306abe7c25662b9429e06dChris Forbesstatic bool setQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value) {
651256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
65139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
6514d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (pCB) {
6515d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryToStateMap[object] = value;
6516d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
6517d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
6518d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (queue_data != dev_data->queueMap.end()) {
6519d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        queue_data->second.queryToStateMap[object] = value;
6520d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
6521d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return false;
6522d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
6523d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
6524bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
65253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
652656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6527b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
65289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
65295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
65303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdBeginQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6531315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_17802415);
65323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
653343ec3f090ca979777b306abe7c25662b9429e06dChris Forbes    }
653443ec3f090ca979777b306abe7c25662b9429e06dChris Forbes    lock.unlock();
653543ec3f090ca979777b306abe7c25662b9429e06dChris Forbes
653643ec3f090ca979777b306abe7c25662b9429e06dChris Forbes    if (skip) return;
653743ec3f090ca979777b306abe7c25662b9429e06dChris Forbes
653843ec3f090ca979777b306abe7c25662b9429e06dChris Forbes    dev_data->dispatch_table.CmdBeginQuery(commandBuffer, queryPool, slot, flags);
653943ec3f090ca979777b306abe7c25662b9429e06dChris Forbes
654043ec3f090ca979777b306abe7c25662b9429e06dChris Forbes    lock.lock();
654143ec3f090ca979777b306abe7c25662b9429e06dChris Forbes    if (pCB) {
654243ec3f090ca979777b306abe7c25662b9429e06dChris Forbes        QueryObject query = {queryPool, slot};
654343ec3f090ca979777b306abe7c25662b9429e06dChris Forbes        pCB->activeQueries.insert(query);
654443ec3f090ca979777b306abe7c25662b9429e06dChris Forbes        pCB->startedQueries.insert(query);
65451ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_BEGINQUERY);
65469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
65479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, pCB);
65485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
655189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
6552946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
655356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6554b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6555946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
6556946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
65575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
6558946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (!cb_state->activeQueries.count(query)) {
6559df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6560315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1ae00652, "DS",
65619b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Ending a query before it was started: queryPool 0x%" PRIx64 ", index %d. %s",
6562315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(queryPool), slot, validation_error_map[VALIDATION_ERROR_1ae00652]);
65635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
6564946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->activeQueries.erase(query);
65655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6566f49bd2b5f4c968a3033b3e5099bbbcff51201575Chris Forbes        cb_state->queryUpdates.emplace_back([=](VkQueue q){return setQueryState(q, commandBuffer, query, true);});
6567baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdEndQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6568315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1ae02415);
6569946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_ENDQUERY, "VkCmdEndQuery()");
6570946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_ENDQUERY);
65719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
65729b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_state);
65735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6574b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6575946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdEndQuery(commandBuffer, queryPool, slot);
65765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6578bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
6579bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint32_t queryCount) {
6580946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
658156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6582b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6583946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
65843a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes        skip |= insideRenderPass(dev_data, cb_state, "vkCmdResetQueryPool()", VALIDATION_ERROR_1c600017);
65853a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes        skip |= ValidateCmd(dev_data, cb_state, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
6586baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdResetQueryPool()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6587315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1c602415);
6588b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
65893a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes
65903a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes    if (skip) return;
65913a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes
65923a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes    dev_data->dispatch_table.CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
65933a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes
65943a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes    lock.lock();
65953a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes    for (uint32_t i = 0; i < queryCount; i++) {
65963a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes        QueryObject query = {queryPool, firstQuery + i};
65973a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes        cb_state->waitedEventsBeforeQueryReset[query] = cb_state->waitedEvents;
6598f49bd2b5f4c968a3033b3e5099bbbcff51201575Chris Forbes        cb_state->queryUpdates.emplace_back([=](VkQueue q){return setQueryState(q, commandBuffer, query, false);});
65993a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes    }
66003a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes    UpdateCmdBufferLastCmd(cb_state, CMD_RESETQUERYPOOL);
66013a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes    addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
66023a4c679ed508b10fd119bb97c127c79b5d126d74Chris Forbes                            {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_state);
66035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
66057ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbesstatic bool IsQueryInvalid(layer_data *dev_data, QUEUE_STATE *queue_data, VkQueryPool queryPool, uint32_t queryIndex) {
66067ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes    QueryObject query = {queryPool, queryIndex};
66077ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes    auto query_data = queue_data->queryToStateMap.find(query);
66087ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes    if (query_data != queue_data->queryToStateMap.end()) {
66097ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes        if (!query_data->second) return true;
66107ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes    } else {
66117ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes        auto it = dev_data->queryToStateMap.find(query);
66127ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes        if (it == dev_data->queryToStateMap.end() || !it->second)
66137ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes            return true;
66147ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes    }
66157ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes
66167ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes    return false;
66177ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes}
66187ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes
66197ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbesstatic bool validateQuery(VkQueue queue, GLOBAL_CB_NODE *pCB, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
66203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
662156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
66227ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes    auto queue_data = GetQueueState(dev_data, queue);
66237ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes    if (!queue_data) return false;
6624d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    for (uint32_t i = 0; i < queryCount; i++) {
66257ffbe89a37f5f822858a35646be0213fd2cd2b08Chris Forbes        if (IsQueryInvalid(dev_data, queue_data, queryPool, firstQuery + i)) {
66263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
66279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
66283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Requesting a copy from query to buffer with invalid query: queryPool 0x%" PRIx64 ", index %d",
66299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(queryPool), firstQuery + i);
6630d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
6631d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
66323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
6633d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
6634d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
6635bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
6636bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
6637bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDeviceSize stride, VkQueryResultFlags flags) {
6638946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
663956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6640b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6641ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
66429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
66439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
66445cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
6645315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_19400674);
6646ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
66475cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
6648ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
6649315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
6650315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, VALIDATION_ERROR_19400672,
6651315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                     "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
6652e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
66535cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
6654e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
66555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
66569f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
6657f49bd2b5f4c968a3033b3e5099bbbcff51201575Chris Forbes        cb_node->queryUpdates.emplace_back([=](VkQueue q) {
6658f49bd2b5f4c968a3033b3e5099bbbcff51201575Chris Forbes            return validateQuery(q, cb_node, queryPool, firstQuery, queryCount);
6659f49bd2b5f4c968a3033b3e5099bbbcff51201575Chris Forbes        });
6660baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdCopyQueryPoolResults()",
6661315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_19402415);
6662946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
6663ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_COPYQUERYPOOLRESULTS);
6664315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, cb_node, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_19400017);
66659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
66669b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_node);
6667ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
6668ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
66695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6670b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6671946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
66724a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset,
66734a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                         stride, flags);
66745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6676bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags,
6677bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                            uint32_t offset, uint32_t size, const void *pValues) {
6678946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
667956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6680b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6681946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
6682946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
6683baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdPushConstants()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6684315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1bc02415);
6685946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
6686946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_PUSHCONSTANTS);
66875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6688946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    skip |= validatePushConstantRange(dev_data, offset, size, "vkCmdPushConstants()");
66899e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if (0 == stageFlags) {
6690df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6691315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1bc2dc03, "DS",
6692315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "vkCmdPushConstants() call has no stageFlags set. %s", validation_error_map[VALIDATION_ERROR_1bc2dc03]);
66939e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
66949e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz
6695bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // Check if specified push constant range falls within a pipeline-defined range which has matching stageFlags.
6696bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // The spec doesn't seem to disallow having multiple push constant ranges with the
6697bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // same offset and size, but different stageFlags.  So we can't just check the
6698bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // stageFlags in the first range with matching offset and size.
6699bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    if (!skip) {
6700bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        const auto &ranges = getPipelineLayout(dev_data, layout)->push_constant_ranges;
6701bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        bool found_matching_range = false;
6702bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        for (const auto &range : ranges) {
6703bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz            if ((stageFlags == range.stageFlags) && (offset >= range.offset) && (offset + size <= range.offset + range.size)) {
6704bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz                found_matching_range = true;
670515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                break;
6706a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz            }
67079e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
6708bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        if (!found_matching_range) {
6709315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6710315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1bc002de, "DS",
6711315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            "vkCmdPushConstants() stageFlags = 0x%" PRIx32
6712315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            " do not match the stageFlags in any of the ranges with"
6713315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            " offset = %d and size = %d in pipeline layout 0x%" PRIx64 ". %s",
6714315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            (uint32_t)stageFlags, offset, size, HandleToUint64(layout),
6715315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1bc002de]);
671615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        }
67175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6718b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6719946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
67205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6722bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
6723bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             VkQueryPool queryPool, uint32_t slot) {
6724946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
672556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6726b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6727946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
6728946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
67295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
6730f49bd2b5f4c968a3033b3e5099bbbcff51201575Chris Forbes        cb_state->queryUpdates.emplace_back([=](VkQueue q) {return setQueryState(q, commandBuffer, query, true);});
6731baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWriteTimestamp()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6732315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1e802415);
6733946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
6734946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WRITETIMESTAMP);
67355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6736b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6737946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
67385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
67406600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinskistatic bool MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference *attachments,
67419bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       const VkFramebufferCreateInfo *fbci, VkImageUsageFlagBits usage_flag,
67429bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
6743946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
67446600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
67456600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    for (uint32_t attach = 0; attach < count; attach++) {
67466600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        if (attachments[attach].attachment != VK_ATTACHMENT_UNUSED) {
67476600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Attachment counts are verified elsewhere, but prevent an invalid access
67486600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (attachments[attach].attachment < fbci->attachmentCount) {
67496600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                const VkImageView *image_view = &fbci->pAttachments[attachments[attach].attachment];
67509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, *image_view);
675179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (view_state) {
67529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    const VkImageCreateInfo *ici = &GetImageState(dev_data, view_state->create_info.image)->createInfo;
67536600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    if (ici != nullptr) {
67546600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        if ((ici->usage & usage_flag) == 0) {
6755df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
6756df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                            VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, error_code, "DS",
6757946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "vkCreateFramebuffer:  Framebuffer Attachment (%d) conflicts with the image's "
6758946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "IMAGE_USAGE flags (%s). %s",
6759946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            attachments[attach].attachment, string_VkImageUsageFlagBits(usage_flag),
6760946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            validation_error_map[error_code]);
67616600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        }
67626600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    }
67636600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                }
67646600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
67656600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
67666600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
6767946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    return skip;
67686600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
67696600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
6770d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// Validate VkFramebufferCreateInfo which includes:
6771d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// 1. attachmentCount equals renderPass attachmentCount
67725ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 2. corresponding framebuffer and renderpass attachments have matching formats
67735ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 3. corresponding framebuffer and renderpass attachments have matching sample counts
67745ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 4. fb attachments only have a single mip level
67755ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 5. fb attachment dimensions are each at least as large as the fb
67765ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 6. fb attachments use idenity swizzle
67775ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 7. fb attachments used by renderPass for color/input/ds have correct usage bit set
67786fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis// 8. fb dimensions are within physical device limits
6779d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlisstatic bool ValidateFramebufferCreateInfo(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
67803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
67816600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
67829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto rp_state = GetRenderPassState(dev_data, pCreateInfo->renderPass);
6783127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    if (rp_state) {
6784127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        const VkRenderPassCreateInfo *rpci = rp_state->createInfo.ptr();
6785d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        if (rpci->attachmentCount != pCreateInfo->attachmentCount) {
67863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(
6787d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
6788315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                HandleToUint64(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_094006d8, "DS",
6789d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachmentCount of %u does not match attachmentCount of %u of "
67909bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "renderPass (0x%" PRIxLEAST64 ") being used to create Framebuffer. %s",
67919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                pCreateInfo->attachmentCount, rpci->attachmentCount, HandleToUint64(pCreateInfo->renderPass),
6792315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                validation_error_map[VALIDATION_ERROR_094006d8]);
67935ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        } else {
679441ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis            // attachmentCounts match, so make sure corresponding attachment details line up
67955ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            const VkImageView *image_views = pCreateInfo->pAttachments;
67965ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
67979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, image_views[i]);
679812d5600c2f9e32343016fd944432ba95df370797Tobin Ehlis                auto &ivci = view_state->create_info;
679979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.format != rpci->pAttachments[i].format) {
68003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
68015ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
6802315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_094006e0, "DS",
68039bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has format of %s that does not match "
68049bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the format of "
68059bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
680679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkFormat(ivci.format), string_VkFormat(rpci->pAttachments[i].format),
6807315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_094006e0]);
68085ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
68099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                const VkImageCreateInfo *ici = &GetImageState(dev_data, ivci.image)->createInfo;
68105ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                if (ici->samples != rpci->pAttachments[i].samples) {
68113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
681241ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
6813315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_094006e2, "DS",
68149bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has %s samples that do not match "
68159bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the %s samples used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
681641ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        i, string_VkSampleCountFlagBits(ici->samples), string_VkSampleCountFlagBits(rpci->pAttachments[i].samples),
6817315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_094006e2]);
68185ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
68195ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                // Verify that view only has a single mip level
682079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.subresourceRange.levelCount != 1) {
68213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
6822315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_094006e6, "DS",
68233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has mip levelCount of %u "
68243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "but only a single mip level (levelCount ==  1) is allowed when creating a Framebuffer. %s",
6825315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, ivci.subresourceRange.levelCount, validation_error_map[VALIDATION_ERROR_094006e6]);
68265ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
682779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                const uint32_t mip_level = ivci.subresourceRange.baseMipLevel;
6828aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_width = max(1u, ici->extent.width >> mip_level);
6829aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_height = max(1u, ici->extent.height >> mip_level);
683079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if ((ivci.subresourceRange.layerCount < pCreateInfo->layers) || (mip_width < pCreateInfo->width) ||
6831aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    (mip_height < pCreateInfo->height)) {
68322c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                    skip |= log_msg(
68332c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
6834315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006e4, "DS",
68352c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has dimensions smaller "
68362c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "than the corresponding framebuffer dimensions. Here are the respective dimensions for attachment #%u, "
68372c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "framebuffer:\n"
68382c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "width: %u, %u\n"
68392c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "height: %u, %u\n"
68402c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "layerCount: %u, %u\n%s",
68412c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        i, ivci.subresourceRange.baseMipLevel, i, mip_width, pCreateInfo->width, mip_height, pCreateInfo->height,
6842315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        ivci.subresourceRange.layerCount, pCreateInfo->layers, validation_error_map[VALIDATION_ERROR_094006e4]);
68435ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
684479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (((ivci.components.r != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.r != VK_COMPONENT_SWIZZLE_R)) ||
684579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.g != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.g != VK_COMPONENT_SWIZZLE_G)) ||
684679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.b != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.b != VK_COMPONENT_SWIZZLE_B)) ||
684779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.a != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.a != VK_COMPONENT_SWIZZLE_A))) {
68483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
68495b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
6850315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006e8, "DS",
6851da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has non-identy swizzle. All framebuffer "
6852da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "attachments must have been created with the identity swizzle. Here are the actual swizzle values:\n"
6853da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "r swizzle = %s\n"
6854da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "g swizzle = %s\n"
6855da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "b swizzle = %s\n"
68569bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "a swizzle = %s\n"
68579bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s",
685879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkComponentSwizzle(ivci.components.r), string_VkComponentSwizzle(ivci.components.g),
68599bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        string_VkComponentSwizzle(ivci.components.b), string_VkComponentSwizzle(ivci.components.a),
6860315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006e8]);
68615ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
68625ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            }
6863d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        }
68645ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        // Verify correct attachment usage flags
68656600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        for (uint32_t subpass = 0; subpass < rpci->subpassCount; subpass++) {
68666600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify input attachments:
68673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
68689bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].inputAttachmentCount, rpci->pSubpasses[subpass].pInputAttachments,
6869315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           pCreateInfo, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VALIDATION_ERROR_094006de);
68706600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify color attachments:
68713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
68729bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].colorAttachmentCount, rpci->pSubpasses[subpass].pColorAttachments,
6873315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           pCreateInfo, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VALIDATION_ERROR_094006da);
68746600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify depth/stencil attachments:
68756600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (rpci->pSubpasses[subpass].pDepthStencilAttachment != nullptr) {
68763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= MatchUsage(dev_data, 1, rpci->pSubpasses[subpass].pDepthStencilAttachment, pCreateInfo,
6877315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                   VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VALIDATION_ERROR_094006dc);
68786600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
68796600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
68806600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
68816fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    // Verify FB dimensions are within physical device limits
68829bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->width > dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth) {
68833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
6884315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006ec, "DS",
68853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width exceeds physical device limits. "
68863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested width: %u, device max: %u\n"
68873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
68883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->width, dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth,
6889315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006ec]);
68909bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
68919bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->height > dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight) {
68923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
6893315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006f0, "DS",
68943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height exceeds physical device limits. "
68953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested height: %u, device max: %u\n"
68963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
68973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->height, dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight,
6898315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006f0]);
68999bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
69009bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->layers > dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers) {
69013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
6902315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006f4, "DS",
69033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers exceeds physical device limits. "
69043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested layers: %u, device max: %u\n"
69053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
69063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->layers, dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers,
6907315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006f4]);
69086fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    }
6909c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    // Verify FB dimensions are greater than zero
6910c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->width <= 0) {
6911c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
6912315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006ea, "DS",
6913c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width must be greater than zero. %s",
6914315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006ea]);
6915c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
6916c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->height <= 0) {
6917c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
6918315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006ee, "DS",
6919c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height must be greater than zero. %s",
6920315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006ee]);
6921c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
6922c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->layers <= 0) {
6923c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
6924315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006f2, "DS",
6925c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers must be greater than zero. %s",
6926315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006f2]);
6927c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
69283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
69296600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
69306600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
693164c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis// Validate VkFramebufferCreateInfo state prior to calling down chain to create Framebuffer object
693264c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//  Return true if an error is encountered and callback returns true to skip call down chain
693364c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//   false indicates that call down chain should proceed
693464c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlisstatic bool PreCallValidateCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
693564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    // TODO : Verify that renderPass FB is created with is compatible with FB
69363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
69373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateFramebufferCreateInfo(dev_data, pCreateInfo);
69383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
693964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis}
694064c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
694154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis// CreateFramebuffer state has been validated and call down chain completed so record new framebuffer object
694254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlisstatic void PostCallRecordCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo, VkFramebuffer fb) {
694354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    // Shadow create info and store in map
6944c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    std::unique_ptr<FRAMEBUFFER_STATE> fb_state(
6945c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        new FRAMEBUFFER_STATE(fb, pCreateInfo, dev_data->renderPassMap[pCreateInfo->renderPass]->createInfo.ptr()));
694676f04ca0e692f9f15d5ef7e0c658c24d11f34ebcTobin Ehlis
694754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
694854e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        VkImageView view = pCreateInfo->pAttachments[i];
69499a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, view);
695079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        if (!view_state) {
695154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis            continue;
695254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        }
695354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        MT_FB_ATTACHMENT_INFO fb_info;
6954883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        fb_info.view_state = view_state;
695579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        fb_info.image = view_state->create_info.image;
6956c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        fb_state->attachments.push_back(fb_info);
695754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    }
6958c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    dev_data->frameBufferMap[fb] = std::move(fb_state);
695954e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis}
696054e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis
696189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
6962bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) {
696356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
696464c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
69653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateCreateFramebuffer(dev_data, pCreateInfo);
696664c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    lock.unlock();
696764c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
69683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
696964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
69704a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
69716600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
69725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
697364c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis        lock.lock();
697454e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        PostCallRecordCreateFramebuffer(dev_data, pCreateInfo, *pFramebuffer);
697554e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        lock.unlock();
69765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
69775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
69785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
69804e11bb1277f55311686a42000520791e1db1dd7bbungemanstatic bool FindDependency(const uint32_t index, const uint32_t dependent, const std::vector<DAGNode> &subpass_to_node,
6981e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           std::unordered_set<uint32_t> &processed_nodes) {
69825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If we have already checked this node we have not found a dependency path so return false.
6983cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (processed_nodes.count(index)) return false;
69845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    processed_nodes.insert(index);
69855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
69865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Look for a dependency path. If one exists return true else recurse on the previous nodes.
69874e11bb1277f55311686a42000520791e1db1dd7bbungeman    if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) {
69885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto elem : node.prev) {
6989cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) return true;
69905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
69915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
6992e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        return true;
69935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6994e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
69955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
69974e11bb1277f55311686a42000520791e1db1dd7bbungemanstatic bool CheckDependencyExists(const layer_data *dev_data, const uint32_t subpass,
69983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                  const std::vector<uint32_t> &dependent_subpasses, const std::vector<DAGNode> &subpass_to_node,
69993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                  bool &skip) {
7000e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = true;
70015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through all subpasses that share the same attachment and make sure a dependency exists
70025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
7003cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (static_cast<uint32_t>(subpass) == dependent_subpasses[k]) continue;
70045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const DAGNode &node = subpass_to_node[subpass];
70055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Check for a specified dependency between the two nodes. If one exists we are done.
70065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]);
70075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]);
70085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
70097655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            // If no dependency exits an implicit dependency still might. If not, throw an error.
70105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            std::unordered_set<uint32_t> processed_nodes;
70117655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            if (!(FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) ||
7012bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                  FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes))) {
70133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
70143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
70153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "A dependency between subpasses %d and %d must exist but one is not specified.", subpass,
70163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                dependent_subpasses[k]);
7017e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                result = false;
70185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
70195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
70205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
70225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
70248860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, const int index,
70253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip) {
70265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
70275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If this node writes to the attachment return true as next nodes need to preserve the attachment.
70285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
70295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
7030cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pColorAttachments[j].attachment) return true;
70315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7032a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
7033a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour        if (attachment == subpass.pInputAttachments[j].attachment) return true;
7034a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    }
70355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
7036cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pDepthStencilAttachment->attachment) return true;
70375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7038e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
70395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through previous nodes and see if any of them write to the attachment.
70405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto elem : node.prev) {
70413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        result |= CheckPreserved(dev_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip);
70425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If the attachment was written to by a previous node than this node needs to preserve it.
70445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result && depth > 0) {
7045e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        bool has_preserved = false;
70465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
70475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (subpass.pPreserveAttachments[j] == attachment) {
7048e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                has_preserved = true;
70495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                break;
70505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
70515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7052e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        if (!has_preserved) {
70533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
70543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
70553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
70565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
70575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
70595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7061cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class T>
7062cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskibool isRangeOverlapping(T offset1, T size1, T offset2, T size2) {
70635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
70645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis           ((offset1 > offset2) && (offset1 < (offset2 + size2)));
70655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
70675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
70685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
70695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
70705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7072c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE const *framebuffer,
7073127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                 RENDER_PASS_STATE const *renderPass) {
70743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
7075fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pFramebufferInfo = framebuffer->createInfo.ptr();
7076fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pCreateInfo = renderPass->createInfo.ptr();
7077bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto const &subpass_to_node = renderPass->subpassToNode;
70785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount);
70795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount);
70805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount);
70815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find overlapping attachments
70825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
70835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) {
70845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewi = pFramebufferInfo->pAttachments[i];
70855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewj = pFramebufferInfo->pAttachments[j];
70865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (viewi == viewj) {
70875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
70885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
70895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
70905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
70919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_i = GetImageViewState(dev_data, viewi);
70929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_j = GetImageViewState(dev_data, viewj);
709379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (!view_state_i || !view_state_j) {
70945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
70955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
709679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_i = view_state_i->create_info;
709779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_j = view_state_j->create_info;
709879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (view_ci_i.image == view_ci_j.image && isRegionOverlapping(view_ci_i.subresourceRange, view_ci_j.subresourceRange)) {
70995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
71005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
71015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
71025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
71039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_i = GetImageState(dev_data, view_ci_i.image);
71049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_j = GetImageState(dev_data, view_ci_j.image);
71056d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (!image_data_i || !image_data_j) {
71065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
71075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7108e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            if (image_data_i->binding.mem == image_data_j->binding.mem &&
7109e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                isRangeOverlapping(image_data_i->binding.offset, image_data_i->binding.size, image_data_j->binding.offset,
7110e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                                   image_data_j->binding.size)) {
71115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
71125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
71135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
71145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
71155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
71165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
71175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t attachment = i;
71185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto other_attachment : overlapping_attachments[i]) {
71195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
71209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
7121315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(framebuffer->framebuffer), __LINE__, VALIDATION_ERROR_12200682, "DS",
71229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Attachment %d aliases attachment %d but doesn't "
71239b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
7124315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                attachment, other_attachment, validation_error_map[VALIDATION_ERROR_12200682]);
71255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
71265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
71279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
7128315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(framebuffer->framebuffer), __LINE__, VALIDATION_ERROR_12200682, "DS",
71299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Attachment %d aliases attachment %d but doesn't "
71309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
7131315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                other_attachment, attachment, validation_error_map[VALIDATION_ERROR_12200682]);
71325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
71335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
71345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
71355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find for each attachment the subpasses that use them.
71361c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young    unordered_set<uint32_t> attachmentIndices;
71375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
71385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
71391c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young        attachmentIndices.clear();
71405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
71415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pInputAttachments[j].attachment;
7142cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
71435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            input_attachment_to_subpass[attachment].push_back(i);
71445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
71455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                input_attachment_to_subpass[overlapping_attachment].push_back(i);
71465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
71475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
71485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
71495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pColorAttachments[j].attachment;
7150cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
71515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
71525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
71535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
71545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
71551c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            attachmentIndices.insert(attachment);
71565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
71575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
71585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
71595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
71605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
71615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
71625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
71631c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young
71641c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            if (attachmentIndices.count(attachment)) {
71653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
7166df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
7167df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
71688860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                            "Cannot use same attachment (%u) as both color and depth output in same subpass (%u).", attachment, i);
71691c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            }
71705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
71715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
71725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If there is a dependency needed make sure one exists
71735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
71745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
71755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an input then all subpasses that output must have a dependency relationship
71765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
717793fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pInputAttachments[j].attachment;
7178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
71793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
71805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
71815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
71825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
718393fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pColorAttachments[j].attachment;
7184cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
71853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
71863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip);
71875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
71885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
71895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
71903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
71913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip);
71925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
71935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
71945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
71955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // written.
71965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
71975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
71985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
71993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckPreserved(dev_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip);
72005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
72015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
72023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
72035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
720532f68580aa01aab3e923cb52915a1d3dd4e993c5Chris Forbesstatic bool CreatePassDAG(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo,
7206e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                          std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) {
72073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
72085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
72095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        DAGNode &subpass_node = subpass_to_node[i];
72105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        subpass_node.pass = i;
72115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
72125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
72135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
721466a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL || dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
721566a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            if (dependency.srcSubpass == dependency.dstSubpass) {
72163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
7217df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
7218df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external.");
721966a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            }
722066a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        } else if (dependency.srcSubpass > dependency.dstSubpass) {
72213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
72223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
72233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Depedency graph must be specified such that an earlier pass cannot depend on a later pass.");
72245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (dependency.srcSubpass == dependency.dstSubpass) {
72255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            has_self_dependency[dependency.srcSubpass] = true;
72265c6aacf95832467d52b2fde1130b04bef559573aChris Forbes        } else {
72275c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
72285c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
72295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
72305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
72313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
72325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
7233918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
723489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
7235bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
723656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
72377aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    bool spirv_valid;
7238b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
72397aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    if (PreCallValidateCreateShaderModule(dev_data, pCreateInfo, &spirv_valid))
72407aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
72415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
72424a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult res = dev_data->dispatch_table.CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
72435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
724459ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis    if (res == VK_SUCCESS) {
7245b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
72467aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        unique_ptr<shader_module> new_shader_module(spirv_valid ? new shader_module(pCreateInfo) : new shader_module());
72477aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        dev_data->shaderModuleMap[*pShaderModule] = std::move(new_shader_module);
72485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
72495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
72505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
72524f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateAttachmentIndex(layer_data *dev_data, uint32_t attachment, uint32_t attachment_count, const char *type) {
72533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
72544f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (attachment >= attachment_count && attachment != VK_ATTACHMENT_UNUSED) {
72553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
7256315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_12200684, "DS",
72573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "CreateRenderPass: %s attachment %d must be less than the total number of attachments %d. %s", type,
7258315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        attachment, attachment_count, validation_error_map[VALIDATION_ERROR_12200684]);
72594f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
72603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
72614f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
72624f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
7263bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool IsPowerOfTwo(unsigned x) { return x && !(x & (x - 1)); }
7264805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
72654f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateRenderpassAttachmentUsage(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo) {
72663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
72674f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
72684f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
72694f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS) {
72703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
7271315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_14000698, "DS",
72723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "CreateRenderPass: Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS. %s", i,
7273315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_14000698]);
72744f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
7275ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
72764f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
72774f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pPreserveAttachments[j];
72784f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) {
72793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
7280315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_140006aa, "DS",
72813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "CreateRenderPass:  Preserve attachment (%d) must not be VK_ATTACHMENT_UNUSED. %s", j,
7282315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_140006aa]);
72834f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            } else {
72843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Preserve");
7285ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
7286ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                bool found = (subpass.pDepthStencilAttachment != NULL && subpass.pDepthStencilAttachment->attachment == attachment);
7287ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                for (uint32_t r = 0; !found && r < subpass.inputAttachmentCount; ++r) {
7288ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    found = (subpass.pInputAttachments[r].attachment == attachment);
7289ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
7290ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                for (uint32_t r = 0; !found && r < subpass.colorAttachmentCount; ++r) {
7291ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    found = (subpass.pColorAttachments[r].attachment == attachment) ||
7292ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                            (subpass.pResolveAttachments != NULL && subpass.pResolveAttachments[r].attachment == attachment);
7293ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
7294ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                if (found) {
7295ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    skip |= log_msg(
7296ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
7297315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_140006ac, "DS",
7298ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                        "CreateRenderPass: subpass %u pPreserveAttachments[%u] (%u) must not be used elsewhere in the subpass. %s",
7299315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        i, j, attachment, validation_error_map[VALIDATION_ERROR_140006ac]);
7300ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
73014f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
73024f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
73036a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
7304bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto subpass_performs_resolve =
7305bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            subpass.pResolveAttachments &&
7306bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            std::any_of(subpass.pResolveAttachments, subpass.pResolveAttachments + subpass.colorAttachmentCount,
7307bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        [](VkAttachmentReference ref) { return ref.attachment != VK_ATTACHMENT_UNUSED; });
73086a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
7309805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        unsigned sample_count = 0;
7310805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
73114f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
73124f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment;
73134f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (subpass.pResolveAttachments) {
73144f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                attachment = subpass.pResolveAttachments[j].attachment;
73153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Resolve");
73166a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
73173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                if (!skip && attachment != VK_ATTACHMENT_UNUSED &&
73186a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    pCreateInfo->pAttachments[attachment].samples != VK_SAMPLE_COUNT_1_BIT) {
73193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
7320315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_140006a2, "DS",
73213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "CreateRenderPass:  Subpass %u requests multisample resolve into attachment %u, "
73223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "which must have VK_SAMPLE_COUNT_1_BIT but has %s. %s",
73233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    i, attachment, string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment].samples),
7324315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_140006a2]);
73256a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                }
7326ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
7327ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                if (!skip && subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED &&
7328ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    subpass.pColorAttachments[j].attachment == VK_ATTACHMENT_UNUSED) {
7329ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
7330315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_1400069e, "DS",
7331ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                                    "CreateRenderPass:  Subpass %u requests multisample resolve from attachment %u "
7332ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                                    "which has attachment=VK_ATTACHMENT_UNUSED. %s",
7333315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, attachment, validation_error_map[VALIDATION_ERROR_1400069e]);
7334ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
73354f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
73364f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            attachment = subpass.pColorAttachments[j].attachment;
73373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Color");
73386a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
73393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            if (!skip && attachment != VK_ATTACHMENT_UNUSED) {
7340805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
7341805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
7342bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (subpass_performs_resolve && pCreateInfo->pAttachments[attachment].samples == VK_SAMPLE_COUNT_1_BIT) {
73433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
7344315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_140006a0, "DS",
73453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "CreateRenderPass:  Subpass %u requests multisample resolve from attachment %u "
73463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "which has VK_SAMPLE_COUNT_1_BIT. %s",
7347315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, attachment, validation_error_map[VALIDATION_ERROR_140006a0]);
7348dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                }
7349ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
7350ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                if (subpass_performs_resolve && subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED) {
7351ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    const auto &color_desc = pCreateInfo->pAttachments[attachment];
7352ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    const auto &resolve_desc = pCreateInfo->pAttachments[subpass.pResolveAttachments[j].attachment];
7353ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    if (color_desc.format != resolve_desc.format) {
7354315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        skip |=
7355315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
7356315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_140006a4, "DS",
7357315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    "CreateRenderPass:  Subpass %u pColorAttachments[%u] resolves to an attachment with a "
7358315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    "different format. "
7359315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    "color format: %u, resolve format: %u. %s",
7360315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, j, color_desc.format, resolve_desc.format, validation_error_map[VALIDATION_ERROR_140006a4]);
7361ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    }
7362ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
73636a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes            }
73644f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
7365dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
73664f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
73674f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
73683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Depth stencil");
7369805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
73703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            if (!skip && attachment != VK_ATTACHMENT_UNUSED) {
7371805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
7372805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            }
73734f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
7374dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
73754f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
73764f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pInputAttachments[j].attachment;
73773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Input");
73784f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
7379805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
7380805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        if (sample_count && !IsPowerOfTwo(sample_count)) {
73813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
7382315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_0082b401, "DS",
73833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "CreateRenderPass:  Subpass %u attempts to render to "
73843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "attachments with inconsistent sample counts. %s",
7385315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            i, validation_error_map[VALIDATION_ERROR_0082b401]);
7386805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        }
73874f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
73883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
73894f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
73904f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
73915245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbesstatic void MarkAttachmentFirstUse(RENDER_PASS_STATE *render_pass,
73925245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                                   uint32_t index,
73935245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                                   bool is_read) {
73945245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes    if (index == VK_ATTACHMENT_UNUSED)
73955245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes        return;
73965245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes
73975245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes    if (!render_pass->attachment_first_read.count(index))
73985245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes        render_pass->attachment_first_read[index] = is_read;
73995245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes}
74005245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes
740189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
74024f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
74033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
740456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
74054f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
74064f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
74074f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    // TODO: As part of wrapping up the mem_tracker/core_validation merge the following routine should be consolidated with
74084f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    //       ValidateLayouts.
74093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateRenderpassAttachmentUsage(dev_data, pCreateInfo);
7410208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
74113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].srcStageMask, "vkCreateRenderPass()",
7412315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_13e006b8, VALIDATION_ERROR_13e006bc);
74133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].dstStageMask, "vkCreateRenderPass()",
7414315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_13e006ba, VALIDATION_ERROR_13e006be);
7415208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
74163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
74173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateLayouts(dev_data, device, pCreateInfo);
7418ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    }
7419ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes    lock.unlock();
74204f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
74213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
74224f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
74234f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
74244f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
74254a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
7426ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes
74275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
74284f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        lock.lock();
74294f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
74304f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<bool> has_self_dependency(pCreateInfo->subpassCount);
74314f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount);
743232f68580aa01aab3e923cb52915a1d3dd4e993c5Chris Forbes        skip |= CreatePassDAG(dev_data, pCreateInfo, subpass_to_node, has_self_dependency);
74334f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
7434127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        auto render_pass = unique_ptr<RENDER_PASS_STATE>(new RENDER_PASS_STATE(pCreateInfo));
743598cddf7090b5d5dcc382045867753ef703d1c3d3Chris Forbes        render_pass->renderPass = *pRenderPass;
7436cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->hasSelfDependency = has_self_dependency;
7437cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->subpassToNode = subpass_to_node;
7438db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
743987e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
744087e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
744187e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
74425245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pColorAttachments[j].attachment, false);
74439cde292b1c19c643b7c13018d9834cccfe6ef7eaChris Forbes
74445245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                // resolve attachments are considered to be written
74455245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                if (subpass.pResolveAttachments) {
74465245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                    MarkAttachmentFirstUse(render_pass.get(), subpass.pResolveAttachments[j].attachment, false);
74479cde292b1c19c643b7c13018d9834cccfe6ef7eaChris Forbes                }
744887e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
74495245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes            if (subpass.pDepthStencilAttachment) {
74505245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pDepthStencilAttachment->attachment, false);
745187e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
7452a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
74535245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pInputAttachments[j].attachment, true);
7454a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            }
745587e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        }
7456db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
7457fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        dev_data->renderPassMap[*pRenderPass] = std::move(render_pass);
74585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
74595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
74605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74614f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
7462eb4c61477130f69f48fdf3ac31cb82104181cc73Chris Forbesstatic bool validatePrimaryCommandBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, char const *cmd_name,
74639bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         UNIQUE_VALIDATION_ERROR_CODE error_code) {
74643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
74655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
74663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
74679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCB->commandBuffer), __LINE__, error_code, "DS",
74689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "Cannot execute command %s on a secondary command buffer. %s", cmd_name, validation_error_map[error_code]);
74695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
74703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
74715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
74738860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool VerifyRenderAreaBounds(const layer_data *dev_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
74743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
7475c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    const safe_VkFramebufferCreateInfo *pFramebufferInfo =
74769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        &GetFramebufferState(dev_data, pRenderPassBegin->framebuffer)->createInfo;
7477885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    if (pRenderPassBegin->renderArea.offset.x < 0 ||
7478885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > pFramebufferInfo->width ||
7479885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        pRenderPassBegin->renderArea.offset.y < 0 ||
7480885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.y + pRenderPassBegin->renderArea.extent.height) > pFramebufferInfo->height) {
74813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= static_cast<bool>(log_msg(
7482df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
7483885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            DRAWSTATE_INVALID_RENDER_AREA, "CORE",
7484885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "Cannot execute a render pass with renderArea not within the bound of the "
7485885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "framebuffer. RenderArea: x %d, y %d, width %d, height %d. Framebuffer: width %d, "
7486885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "height %d.",
7487885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.width,
7488885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.extent.height, pFramebufferInfo->width, pFramebufferInfo->height));
7489885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    }
74903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
7491885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine}
7492885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine
74931a65650f856376768d7b03ea2d080aaff87cacfdMark 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
74941a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// [load|store]Op flag must be checked
74951a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// TODO: The memory valid flag in DEVICE_MEM_INFO should probably be split to track the validity of stencil memory separately.
7496cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <typename T>
7497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool FormatSpecificLoadAndStoreOpSettings(VkFormat format, T color_depth_op, T stencil_op, T op) {
7498a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    if (color_depth_op != op && stencil_op != op) {
7499a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski        return false;
7500a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    }
750116769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton    bool check_color_depth_load_op = !FormatIsStencilOnly(format);
750216769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton    bool check_stencil_load_op = FormatIsDepthAndStencil(format) || !check_color_depth_load_op;
7503a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski
75040d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes    return ((check_color_depth_load_op && (color_depth_op == op)) ||
75050d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes            (check_stencil_load_op && (stencil_op == op)));
75061a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski}
75071a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski
7508bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
7509bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkSubpassContents contents) {
75103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
751156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7512b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
75149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr;
75159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr;
7516f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
7517308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski        if (render_pass_state) {
7518cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            uint32_t clear_op_size = 0;  // Make sure pClearValues is at least as large as last LOAD_OP_CLEAR
7519f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeFramebuffer = pRenderPassBegin->framebuffer;
7520308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            for (uint32_t i = 0; i < render_pass_state->createInfo.attachmentCount; ++i) {
7521f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
7522308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                auto pAttachment = &render_pass_state->createInfo.pAttachments[i];
7523bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp, pAttachment->stencilLoadOp,
75241a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski                                                         VK_ATTACHMENT_LOAD_OP_CLEAR)) {
752592bc0680357019834b7529148ab6d73353ce02c7Mark Lobodzinski                    clear_op_size = static_cast<uint32_t>(i) + 1;
752616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
75279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
752816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
752916387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
7530f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
7531db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
7532bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE)) {
753316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
75349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
753516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
753616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
7537f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
7538db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
7539bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD)) {
754016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
75419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
7542f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
754316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
7544f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
754516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                }
7546308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                if (render_pass_state->attachment_first_read[i]) {
754716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
75489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
7549f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
755016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
7551f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
75525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
75535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
75546de3c6ffa0819ee37cd5cecee918b062145e2ff1Tobin Ehlis            if (clear_op_size > pRenderPassBegin->clearValueCount) {
75553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
7556369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
7557315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    HandleToUint64(render_pass_state->renderPass), __LINE__, VALIDATION_ERROR_1200070c, "DS",
7558bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but there must "
7559bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "be at least %u entries in pClearValues array to account for the highest index attachment in renderPass "
7560cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "0x%" PRIx64
7561cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array "
7562bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "is indexed by attachment number so even if some pClearValues entries between 0 and %u correspond to "
7563bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "attachments that aren't cleared they will be ignored. %s",
75649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    pRenderPassBegin->clearValueCount, clear_op_size, HandleToUint64(render_pass_state->renderPass), clear_op_size,
7565315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    clear_op_size - 1, validation_error_map[VALIDATION_ERROR_1200070c]);
7566369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            }
75673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin);
75683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= VerifyFramebufferAndRenderPassLayouts(dev_data, cb_node, pRenderPassBegin,
75693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                          GetFramebufferState(dev_data, pRenderPassBegin->framebuffer));
7570315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= insideRenderPass(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_17a00017);
75713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateDependencies(dev_data, framebuffer, render_pass_state);
7572315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= validatePrimaryCommandBuffer(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_17a00019);
7573315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBeginRenderPass()", VK_QUEUE_GRAPHICS_BIT,
7574315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                          VALIDATION_ERROR_17a02415);
75753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateCmd(dev_data, cb_node, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()");
75761ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(cb_node, CMD_BEGINRENDERPASS);
7577308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            cb_node->activeRenderPass = render_pass_state;
75785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // This is a shallow copy as that is all that is needed for now
7579f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeRenderPassBeginInfo = *pRenderPassBegin;
7580f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpass = 0;
7581f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpassContents = contents;
7582f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->framebuffers.insert(pRenderPassBegin->framebuffer);
7583883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            // Connect this framebuffer and its children to this cmdBuffer
7584883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            AddFramebufferBinding(dev_data, cb_node, framebuffer);
75855f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis            // transition attachments to the correct layouts for beginning of renderPass and first subpass
75865f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis            TransitionBeginRenderPassLayouts(dev_data, cb_node, render_pass_state, framebuffer);
75875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
75885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7589b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
75903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
75914a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
75925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
75935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
759589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
75963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
759756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7598b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
76005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
7601315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_1b600019);
7602315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdNextSubpass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1b602415);
76033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()");
76041ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_NEXTSUBPASS);
7605315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_1b600017);
760680281691386b37385846f21b38e8c9d4b12cc74eChris Forbes
7607fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        auto subpassCount = pCB->activeRenderPass->createInfo.subpassCount;
760880281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        if (pCB->activeSubpass == subpassCount - 1) {
76093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7610315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1b60071a, "DS",
76113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdNextSubpass(): Attempted to advance beyond final subpass. %s",
7612315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1b60071a]);
761380281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        }
76145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7615b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
761696ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
76173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
761896ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
76194a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdNextSubpass(commandBuffer, contents);
762096ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
762196ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    if (pCB) {
7622bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        lock.lock();
7623bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpass++;
7624bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpassContents = contents;
76255f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis        TransitionSubpassLayouts(dev_data, pCB, pCB->activeRenderPass, pCB->activeSubpass,
76269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                 GetFramebufferState(dev_data, pCB->activeRenderPassBeginInfo.framebuffer));
762796ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    }
76285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
763089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) {
76313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
763256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7633b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
76349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pCB = GetCBNode(dev_data, commandBuffer);
763555867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski    FRAMEBUFFER_STATE *framebuffer = NULL;
763658c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes    if (pCB) {
7637127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        RENDER_PASS_STATE *rp_state = pCB->activeRenderPass;
76389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        framebuffer = GetFramebufferState(dev_data, pCB->activeFramebuffer);
7639127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        if (rp_state) {
7640127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            if (pCB->activeSubpass != rp_state->createInfo.subpassCount - 1) {
76413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
76429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
7643315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                VALIDATION_ERROR_1b00071c, "DS", "vkCmdEndRenderPass(): Called before reaching final subpass. %s",
7644315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_1b00071c]);
764502a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes            }
764602a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes
7647127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            for (size_t i = 0; i < rp_state->createInfo.attachmentCount; ++i) {
7648e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
7649127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                auto pAttachment = &rp_state->createInfo.pAttachments[i];
7650bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp, pAttachment->stencilStoreOp,
7651bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VK_ATTACHMENT_STORE_OP_STORE)) {
765258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
76539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
765458c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
765558c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
765658c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
7657db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp,
7658bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE)) {
765958c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
76609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
766158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
766258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
766358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
76645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
76655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
76665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7667315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass()", VALIDATION_ERROR_1b000017);
7668315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass()", VALIDATION_ERROR_1b000019);
7669315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdEndRenderPass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1b002415);
76703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()");
76711ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_ENDRENDERPASS);
76720e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    }
76730e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    lock.unlock();
76740e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
76753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
76760e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
76774a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdEndRenderPass(commandBuffer);
76780e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
76790e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    if (pCB) {
76800e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes        lock.lock();
768155867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        TransitionFinalSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, framebuffer);
768258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeRenderPass = nullptr;
768358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeSubpass = 0;
768458c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeFramebuffer = VK_NULL_HANDLE;
76855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
76865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7688a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, uint32_t primaryAttach,
7689a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                        uint32_t secondaryAttach, const char *msg) {
7690df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7691315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                   HandleToUint64(secondaryBuffer), __LINE__, VALIDATION_ERROR_1b2000c4, "DS",
7692df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "vkCmdExecuteCommands() called w/ invalid Secondary Cmd Buffer 0x%" PRIx64
7693df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   " which has a render pass "
7694df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "that is not compatible with the Primary Cmd Buffer current render pass. "
7695df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "Attachment %u is not compatible with %u: %s. %s",
76969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                   HandleToUint64(secondaryBuffer), primaryAttach, secondaryAttach, msg,
7697315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                   validation_error_map[VALIDATION_ERROR_1b2000c4]);
76985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7700a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
7701a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, uint32_t primaryAttach,
7702a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkCommandBuffer secondaryBuffer, VkRenderPassCreateInfo const *secondaryPassCI,
7703e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                            uint32_t secondaryAttach, bool is_multi) {
77043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
7705a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->attachmentCount <= primaryAttach) {
77065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primaryAttach = VK_ATTACHMENT_UNUSED;
77075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7708a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (secondaryPassCI->attachmentCount <= secondaryAttach) {
77095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondaryAttach = VK_ATTACHMENT_UNUSED;
77105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) {
77123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
77135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED) {
77153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
77163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "The first is unused while the second is not.");
77173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
77185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondaryAttach == VK_ATTACHMENT_UNUSED) {
77203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
77213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "The second is unused while the first is not.");
77223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
77235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7724a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].format != secondaryPassCI->pAttachments[secondaryAttach].format) {
77253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
7726a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different formats.");
77275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7728a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].samples != secondaryPassCI->pAttachments[secondaryAttach].samples) {
77293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
7730a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different samples.");
77315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7732a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (is_multi && primaryPassCI->pAttachments[primaryAttach].flags != secondaryPassCI->pAttachments[secondaryAttach].flags) {
77333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
7734a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different flags.");
77355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
77375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7739a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
7740a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
7741a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *secondaryPassCI, const int subpass, bool is_multi) {
77423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
7743a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &primary_desc = primaryPassCI->pSubpasses[subpass];
7744a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &secondary_desc = secondaryPassCI->pSubpasses[subpass];
77455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
77465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) {
77475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
77485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.inputAttachmentCount) {
77495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_input_attach = primary_desc.pInputAttachments[i].attachment;
77505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
77515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.inputAttachmentCount) {
77525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
77535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
77543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_input_attach, secondaryBuffer,
77553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_input_attach, is_multi);
77565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
77585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) {
77595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
77605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount) {
77615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_color_attach = primary_desc.pColorAttachments[i].attachment;
77625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
77635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount) {
77645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
77655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
77663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_color_attach, secondaryBuffer,
77673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_color_attach, is_multi);
77685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
77695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
77705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
77715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
77725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
77735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
77745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
77753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_resolve_attach, secondaryBuffer,
77763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_resolve_attach, is_multi);
77775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
77795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primary_desc.pDepthStencilAttachment) {
77805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
77815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_desc.pDepthStencilAttachment) {
77835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
77845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_depthstencil_attach, secondaryBuffer,
77863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            secondaryPassCI, secondary_depthstencil_attach, is_multi);
77873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
77885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7790a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// Verify that given renderPass CreateInfo for primary and secondary command buffers are compatible.
7791a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  This function deals directly with the CreateInfo, there are overloaded versions below that can take the renderPass handle and
7792a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  will then feed into this function
7793a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
7794a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
7795a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *secondaryPassCI) {
77963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
7797a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis
7798a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->subpassCount != secondaryPassCI->subpassCount) {
77993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
78009b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(primaryBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
78013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer 0x%" PRIx64
78023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        " that has a subpassCount of %u that is incompatible with the primary Cmd Buffer 0x%" PRIx64
78033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        " that has a subpassCount of %u.",
78049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(secondaryBuffer), secondaryPassCI->subpassCount, HandleToUint64(primaryBuffer),
78059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        primaryPassCI->subpassCount);
7806a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    } else {
7807a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        for (uint32_t i = 0; i < primaryPassCI->subpassCount; ++i) {
78083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateSubpassCompatibility(dev_data, primaryBuffer, primaryPassCI, secondaryBuffer, secondaryPassCI, i,
78093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                 primaryPassCI->subpassCount > 1);
7810a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
78115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
78123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
78135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7815e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
7816e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) {
78173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
78185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pSubCB->beginInfo.pInheritanceInfo) {
78193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
78205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7821c5b97dda856ff837638b3ebb7e231d5507c495a3Chris Forbes    VkFramebuffer primary_fb = pCB->activeFramebuffer;
78225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
78235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_fb != VK_NULL_HANDLE) {
78245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (primary_fb != secondary_fb) {
78253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7826315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(primaryBuffer), __LINE__, VALIDATION_ERROR_1b2000c6, "DS",
78273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdExecuteCommands() called w/ invalid secondary command buffer 0x%" PRIx64
78283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " which has a framebuffer 0x%" PRIx64
78293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " that is not the same as the primary command buffer's current active framebuffer 0x%" PRIx64 ". %s",
78309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(secondaryBuffer), HandleToUint64(secondary_fb), HandleToUint64(primary_fb),
7831315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1b2000c6]);
78325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
78339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto fb = GetFramebufferState(dev_data, secondary_fb);
7834e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes        if (!fb) {
78353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
78369b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(primaryBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
78373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
78383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "which has invalid framebuffer 0x%" PRIx64 ".",
78399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            (void *)secondaryBuffer, HandleToUint64(secondary_fb));
78403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            return skip;
78415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
78429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_renderpass = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
7843a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if (cb_renderpass->renderPass != fb->createInfo.renderPass) {
78443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb->renderPassCreateInfo.ptr(), secondaryBuffer,
78453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                    cb_renderpass->createInfo.ptr());
7846a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
78475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
78483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
78495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7851e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
78523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
78535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<int> activeTypes;
78545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pCB->activeQueries) {
78555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
78565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end()) {
78575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
78585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pSubCB->beginInfo.pInheritanceInfo) {
78595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
78605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) {
78619b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    skip |= log_msg(
78629b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7863315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_1b2000d0, "DS",
78649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
78659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "which has invalid active query pool 0x%" PRIx64
78669b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        ". Pipeline statistics is being queried so the command "
78679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "buffer must have all bits set on the queryPool. %s",
7868315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        pCB->commandBuffer, HandleToUint64(queryPoolData->first), validation_error_map[VALIDATION_ERROR_1b2000d0]);
78695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
78705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
78715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            activeTypes.insert(queryPoolData->second.createInfo.queryType);
78725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
78735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
78745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pSubCB->startedQueries) {
78755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
78765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
78779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
78789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
78799b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
78809b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "which has invalid active query pool 0x%" PRIx64
78819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "of type %d but a query of that type has been started on "
78829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "secondary Cmd Buffer 0x%p.",
78839b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pCB->commandBuffer, HandleToUint64(queryPoolData->first), queryPoolData->second.createInfo.queryType,
78849b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pSubCB->commandBuffer);
78855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
78865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
78877bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
78889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto primary_pool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
78899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto secondary_pool = GetCommandPoolNode(dev_data, pSubCB->createInfo.commandPool);
78907bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    if (primary_pool && secondary_pool && (primary_pool->queueFamilyIndex != secondary_pool->queueFamilyIndex)) {
78913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
7892226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
78939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(pSubCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_FAMILY, "DS",
7894226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "vkCmdExecuteCommands(): Primary command buffer 0x%p"
7895226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    " created in queue family %d has secondary command buffer 0x%p created in queue family %d.",
7896226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    pCB->commandBuffer, primary_pool->queueFamilyIndex, pSubCB->commandBuffer, secondary_pool->queueFamilyIndex);
78977bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
78987bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
78993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
79005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7902bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
7903bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
79043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
790556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7906b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
79079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
79085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
79095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        GLOBAL_CB_NODE *pSubCB = NULL;
79105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < commandBuffersCount; i++) {
79119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            pSubCB = GetCBNode(dev_data, pCommandBuffers[i]);
79120a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            assert(pSubCB);
79130a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) {
79143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
7915df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7916315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_1b2000b0, "DS",
7917df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "vkCmdExecuteCommands() called w/ Primary Cmd Buffer 0x%p in element %u of pCommandBuffers "
7918df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "array. All cmd buffers in pCommandBuffers array must be secondary. %s",
7919315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCommandBuffers[i], i, validation_error_map[VALIDATION_ERROR_1b2000b0]);
7920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (pCB->activeRenderPass) {  // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
79210de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                if (pSubCB->beginInfo.pInheritanceInfo != nullptr) {
79220de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    auto secondary_rp_state = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
79230de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
79240de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        skip |= log_msg(
79250de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7926315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_1b2000c0, "DS",
79270de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) executed within render pass (0x%" PRIxLEAST64
79280de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT "
79290de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "set. %s",
79300de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            pCommandBuffers[i], HandleToUint64(pCB->activeRenderPass->renderPass),
7931315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1b2000c0]);
79320de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    } else {
79330de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        // Make sure render pass is compatible with parent command buffer pass if has continue
79340de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        if (pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) {
79350de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            skip |=
79360de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                                validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass->createInfo.ptr(),
79373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                                pCommandBuffers[i], secondary_rp_state->createInfo.ptr());
79380de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        }
79390de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        //  If framebuffer for secondary CB is not NULL, then it must match active FB from primaryCB
79400de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        skip |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB);
79410de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    }
79420de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    string errorString = "";
79430de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    // secondaryCB must have been created w/ RP compatible w/ primaryCB active renderpass
79440de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    if ((pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) &&
79450de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(),
79460de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                                                         secondary_rp_state->createInfo.ptr(), errorString)) {
79470de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        skip |= log_msg(
79480de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
79490de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            HandleToUint64(pCommandBuffers[i]), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
79500de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) w/ render pass (0x%" PRIxLEAST64
79510de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            ") is incompatible w/ primary command buffer (0x%p) w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
79520de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            pCommandBuffers[i], HandleToUint64(pSubCB->beginInfo.pInheritanceInfo->renderPass), commandBuffer,
79530de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            HandleToUint64(pCB->activeRenderPass->renderPass), errorString.c_str());
7954a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                    }
79555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
79565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
79575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO(mlentine): Move more logic into this method
79583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB);
7959315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= validateCommandBufferState(dev_data, pSubCB, "vkCmdExecuteCommands()", 0, VALIDATION_ERROR_1b2000b2);
79605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
79619b2582dc67737351a72fbeb82e9e6e8cdff7a026Chris Forbes                if (pSubCB->in_use.load() || pCB->linkedCommandBuffers.count(pSubCB)) {
79623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
79639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCB->commandBuffer), __LINE__,
7964315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    VALIDATION_ERROR_1b2000b4, "DS",
79653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Attempt to simultaneously execute command buffer 0x%p"
79663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set! %s",
7967315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    pCB->commandBuffer, validation_error_map[VALIDATION_ERROR_1b2000b4]);
79685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
79695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
79705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
79713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
79725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
79739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
7974226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) "
7975226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer "
7976226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "(0x%p) to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
797783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "set, even though it does.",
7978226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], pCB->commandBuffer);
79795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
79805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
79815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7982f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes            if (!pCB->activeQueries.empty() && !dev_data->enabled_features.inheritedQueries) {
79833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
7984cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7985315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_1b2000ca, "DS",
7986cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer "
7987cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "(0x%p) cannot be submitted with a query in "
7988cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "flight and inherited queries not "
7989cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "supported on this device. %s",
7990315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCommandBuffers[i], validation_error_map[VALIDATION_ERROR_1b2000ca]);
79915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
79929b2582dc67737351a72fbeb82e9e6e8cdff7a026Chris Forbes            // TODO: separate validate from update! This is very tangled.
79938567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            // Propagate layout transitions to the primary cmd buffer
79948567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            for (auto ilm_entry : pSubCB->imageLayoutMap) {
799555867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski                SetLayout(dev_data, pCB, ilm_entry.first, ilm_entry.second);
79968567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            }
79975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pSubCB->primaryCommandBuffer = pCB->commandBuffer;
79981a3660584634742a3297915c94768d73f360e794Chris Forbes            pCB->linkedCommandBuffers.insert(pSubCB);
79991a3660584634742a3297915c94768d73f360e794Chris Forbes            pSubCB->linkedCommandBuffers.insert(pCB);
8000d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            for (auto &function : pSubCB->queryUpdates) {
8001d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine                pCB->queryUpdates.push_back(function);
8002d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            }
80035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8004315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteCommands()", VALIDATION_ERROR_1b200019);
8005315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
8006315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdExecuteCommands()",
8007315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_1b202415);
8008f5a52627a6576d3d532cd1f2e1be6d9987aeda7fChris Forbes        skip |= ValidateCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteCommands()");
80091ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_EXECUTECOMMANDS);
80105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8011b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
80123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
80135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8015bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
8016bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         void **ppData) {
801756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
80185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
80193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
80205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
8021b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
80229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
8023cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    if (mem_info) {
8024f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        // TODO : This could me more fine-grained to track just region that is valid
8025f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        mem_info->global_valid = true;
8026623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        auto end_offset = (VK_WHOLE_SIZE == size) ? mem_info->alloc_info.allocationSize - 1 : offset + size - 1;
80273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateMapImageLayouts(dev_data, device, mem_info, offset, end_offset);
8028cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        // TODO : Do we need to create new "bound_range" for the mapped range?
8029623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        SetMemRangesValid(dev_data, mem_info, offset, end_offset);
8030cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        if ((dev_data->phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
8031b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
80323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
8033315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           HandleToUint64(mem), __LINE__, VALIDATION_ERROR_31200554, "MEM",
80343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj 0x%" PRIxLEAST64 ". %s",
8035315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           HandleToUint64(mem), validation_error_map[VALIDATION_ERROR_31200554]);
80365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
80375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
80383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateMapMemRange(dev_data, mem, offset, size);
8039b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
80405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
80413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
80424a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.MapMemory(device, mem, offset, size, flags, ppData);
80437c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        if (VK_SUCCESS == result) {
80447c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.lock();
8045cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : What's the point of this range? See comment on creating new "bound_range" above, which may replace this
80467c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            storeMemRanges(dev_data, mem, offset, size);
80475f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            initializeAndTrackMemory(dev_data, mem, offset, size, ppData);
80487c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.unlock();
80497c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        }
80505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
80515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
80525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
805489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL UnmapMemory(VkDevice device, VkDeviceMemory mem) {
805556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
80563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
80575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8058b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
80593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= deleteMemRanges(dev_data, mem);
8060b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
80613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
80624a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UnmapMemory(device, mem);
80635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
80645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
80668860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool validateMemoryIsMapped(layer_data *dev_data, const char *funcName, uint32_t memRangeCount,
8067e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                   const VkMappedMemoryRange *pMemRanges) {
8068c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    bool skip = false;
80695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < memRangeCount; ++i) {
80709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, pMemRanges[i].memory);
807157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
8072f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            if (pMemRanges[i].size == VK_WHOLE_SIZE) {
8073f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if (mem_info->mem_range.offset > pMemRanges[i].offset) {
8074315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    skip |=
8075315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
8076315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pMemRanges[i].memory), __LINE__, VALIDATION_ERROR_0c20055c, "MEM",
8077315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER
8078315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                ") is less than Memory Object's offset "
8079315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "(" PRINTF_SIZE_T_SPECIFIER "). %s",
8080315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                funcName, static_cast<size_t>(pMemRanges[i].offset),
8081315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                static_cast<size_t>(mem_info->mem_range.offset), validation_error_map[VALIDATION_ERROR_0c20055c]);
8082f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
8083f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            } else {
8084f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                const uint64_t data_end = (mem_info->mem_range.size == VK_WHOLE_SIZE)
8085f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              ? mem_info->alloc_info.allocationSize
8086f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              : (mem_info->mem_range.offset + mem_info->mem_range.size);
8087f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if ((mem_info->mem_range.offset > pMemRanges[i].offset) ||
8088f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                    (data_end < (pMemRanges[i].offset + pMemRanges[i].size))) {
8089c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski                    skip |=
8090f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
8091315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pMemRanges[i].memory), __LINE__, VALIDATION_ERROR_0c20055a, "MEM",
8092f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "%s: Flush/Invalidate size or offset (" PRINTF_SIZE_T_SPECIFIER ", " PRINTF_SIZE_T_SPECIFIER
8093f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                ") exceed the Memory Object's upper-bound "
8094f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "(" PRINTF_SIZE_T_SPECIFIER "). %s",
8095f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
8096f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(data_end),
8097315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_0c20055a]);
8098f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
80995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
81005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8102c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    return skip;
81035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8105bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic bool ValidateAndCopyNoncoherentMemoryToDriver(layer_data *dev_data, uint32_t mem_range_count,
8106bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                     const VkMappedMemoryRange *mem_ranges) {
8107bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    bool skip = false;
8108bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
81099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
811057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
81115f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            if (mem_info->shadow_copy) {
81125f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
81135f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                        ? mem_info->mem_range.size
8114d8a53ade6b5501256798a8b4ec0bc14f72adc1faTobin Ehlis                                        : (mem_info->alloc_info.allocationSize - mem_info->mem_range.offset);
81155f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                char *data = static_cast<char *>(mem_info->shadow_copy);
81165f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = 0; j < mem_info->shadow_pad_size; ++j) {
81175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
81189b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        skip |= log_msg(
81199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
81209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem_ranges[i].memory), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
81219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Memory underflow was detected on mem obj 0x%" PRIxLEAST64, HandleToUint64(mem_ranges[i].memory));
81225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
81235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
81245f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = (size + mem_info->shadow_pad_size); j < (2 * mem_info->shadow_pad_size + size); ++j) {
81255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
81269b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        skip |= log_msg(
81279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
81289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem_ranges[i].memory), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
81299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Memory overflow was detected on mem obj 0x%" PRIxLEAST64, HandleToUint64(mem_ranges[i].memory));
81305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
81315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
81325f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                memcpy(mem_info->p_driver_data, static_cast<void *>(data + mem_info->shadow_pad_size), (size_t)(size));
81335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
81345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8136bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    return skip;
81375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8139bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic void CopyNoncoherentMemoryFromDriver(layer_data *dev_data, uint32_t mem_range_count, const VkMappedMemoryRange *mem_ranges) {
8140bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
81419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
81425f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info && mem_info->shadow_copy) {
81435f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
81445f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    ? mem_info->mem_range.size
81455f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    : (mem_info->alloc_info.allocationSize - mem_ranges[i].offset);
81465f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            char *data = static_cast<char *>(mem_info->shadow_copy);
81475f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            memcpy(data + mem_info->shadow_pad_size, mem_info->p_driver_data, (size_t)(size));
81489e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski        }
81499e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski    }
81509e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski}
81519e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski
8152ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinskistatic bool ValidateMappedMemoryRangeDeviceLimits(layer_data *dev_data, const char *func_name, uint32_t mem_range_count,
8153ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                                                  const VkMappedMemoryRange *mem_ranges) {
8154ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    bool skip = false;
8155ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
8156ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        uint64_t atom_size = dev_data->phys_dev_properties.properties.limits.nonCoherentAtomSize;
815716769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(mem_ranges[i].offset, atom_size) != 0) {
8158df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
8159315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(mem_ranges->memory), __LINE__, VALIDATION_ERROR_0c20055e, "MEM",
8160ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Offset in pMemRanges[%d] is 0x%" PRIxLEAST64
8161ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
8162315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            func_name, i, mem_ranges[i].offset, atom_size, validation_error_map[VALIDATION_ERROR_0c20055e]);
8163ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
816416769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if ((mem_ranges[i].size != VK_WHOLE_SIZE) && (SafeModulo(mem_ranges[i].size, atom_size) != 0)) {
8165df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
8166315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(mem_ranges->memory), __LINE__, VALIDATION_ERROR_0c200560, "MEM",
8167ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Size in pMemRanges[%d] is 0x%" PRIxLEAST64
8168ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
8169315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            func_name, i, mem_ranges[i].size, atom_size, validation_error_map[VALIDATION_ERROR_0c200560]);
8170ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
8171ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    }
8172ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    return skip;
8173ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski}
8174ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski
817580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateFlushMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
817680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                   const VkMappedMemoryRange *mem_ranges) {
817780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
817880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
817980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= ValidateAndCopyNoncoherentMemoryToDriver(dev_data, mem_range_count, mem_ranges);
818080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkFlushMappedMemoryRanges", mem_range_count, mem_ranges);
818180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
818280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
818380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
8184bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
8185bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                       const VkMappedMemoryRange *pMemRanges) {
81865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
818756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
81885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
818980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateFlushMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
81904a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
81915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
81925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
81935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
819580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
819680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                        const VkMappedMemoryRange *mem_ranges) {
819780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
819880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
819980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkInvalidateMappedMemoryRanges", mem_range_count, mem_ranges);
820080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
820180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
820280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
820380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic void PostCallRecordInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
820480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                       const VkMappedMemoryRange *mem_ranges) {
820580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
820680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    // Update our shadow copy with modified driver data
820780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    CopyNoncoherentMemoryFromDriver(dev_data, mem_range_count, mem_ranges);
820880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
820980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
8210bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL InvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
8211bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                            const VkMappedMemoryRange *pMemRanges) {
82125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
821356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
82145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
821580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
82164a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
821780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        if (result == VK_SUCCESS) {
821880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski            PostCallRecordInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges);
821980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        }
82205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
82215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
82225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
82235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8224160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic bool PreCallValidateBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
8225160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                           VkDeviceSize memoryOffset) {
82260109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski    bool skip = false;
82271facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
8228160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
822994c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        // Track objects tied to memory
82309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t image_handle = HandleToUint64(image);
82317a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip = ValidateSetMemBinding(dev_data, mem, image_handle, kVulkanObjectTypeImage, "vkBindImageMemory()");
8232ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        if (!image_state->memory_requirements_checked) {
8233ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // There's not an explicit requirement in the spec to call vkGetImageMemoryRequirements() prior to calling
8234341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // BindImageMemory but it's implied in that memory being bound must conform with VkMemoryRequirements from
8235341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // vkGetImageMemoryRequirements()
82360109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
82370109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle, __LINE__, DRAWSTATE_INVALID_IMAGE, "DS",
82380109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            "vkBindImageMemory(): Binding memory to image 0x%" PRIxLEAST64
82390109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            " but vkGetImageMemoryRequirements() has not been called on that image.",
82400109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle);
8241ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // Make the call for them so we can verify the state
8242ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.unlock();
8243341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            dev_data->dispatch_table.GetImageMemoryRequirements(dev_data->device, image, &image_state->requirements);
8244ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.lock();
8245ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        }
824647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
82470ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Validate bound memory range information
82489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
824957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
82500ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= ValidateInsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
82510ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                                   image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR, "vkBindImageMemory()");
825274300755ed9ec780d6073af71e47f201217008d6Cort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, image_state->requirements.memoryTypeBits, "vkBindImageMemory()",
8253315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        VALIDATION_ERROR_1740082e);
825447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
8255160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
8256160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements alignment
825716769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(memoryOffset, image_state->requirements.alignment) != 0) {
8258160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
8259315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            image_handle, __LINE__, VALIDATION_ERROR_17400830, "DS",
8260160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindImageMemory(): memoryOffset is 0x%" PRIxLEAST64
8261160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be an integer multiple of the "
8262160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
8263160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
8264315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            memoryOffset, image_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_17400830]);
8265160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
8266160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
8267160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements size
8268160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        if (image_state->requirements.size > mem_info->alloc_info.allocationSize - memoryOffset) {
8269160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
8270315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            image_handle, __LINE__, VALIDATION_ERROR_17400832, "DS",
8271160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindImageMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
8272160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be at least as large as "
8273160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
8274160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
8275160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            mem_info->alloc_info.allocationSize - memoryOffset, image_state->requirements.size,
8276315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_17400832]);
8277160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
8278341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
8279341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    return skip;
8280341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
828147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
8282160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic void PostCallRecordBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
8283160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                          VkDeviceSize memoryOffset) {
8284341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (image_state) {
8285160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
82860ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Track bound memory range information
82870ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto mem_info = GetMemObjInfo(dev_data, mem);
82880ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        if (mem_info) {
82890ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            InsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
82900ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                   image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR);
82910ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
82920ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
8293c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
82949b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t image_handle = HandleToUint64(image);
82957a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        SetMemBinding(dev_data, mem, image_handle, kVulkanObjectTypeImage, "vkBindImageMemory()");
8296c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
8297341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.mem = mem;
8298341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.offset = memoryOffset;
8299341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.size = image_state->requirements.size;
8300341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
8301341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
8302341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton
8303341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
8304341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
8305341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
8306160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    auto image_state = GetImageState(dev_data, image);
8307160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    bool skip = PreCallValidateBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
8308341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (!skip) {
8309341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        result = dev_data->dispatch_table.BindImageMemory(device, image, mem, memoryOffset);
8310341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        if (result == VK_SUCCESS) {
8311160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            PostCallRecordBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
831294c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        }
83135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
83145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
83155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
83165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
831789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL SetEvent(VkDevice device, VkEvent event) {
83183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
83193ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
832056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
8321b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
83229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto event_state = GetEventNode(dev_data, event);
83234710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    if (event_state) {
83244710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->needsSignaled = false;
83254710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->stageMask = VK_PIPELINE_STAGE_HOST_BIT;
83264710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state->write_in_use) {
83273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
83289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(event), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
83293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Cannot call vkSetEvent() on event 0x%" PRIxLEAST64 " that is already in use by a command buffer.",
83309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(event));
83313ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis        }
83323ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    }
8333b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
83346fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // Host setting event is visible to all queues immediately so update stageMask for any queue that's seen this event
83356fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // TODO : For correctness this needs separate fix to verify that app doesn't make incorrect assumptions about the
83366fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // ordering of this command in relation to vkCmd[Set|Reset]Events (see GH297)
83376fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    for (auto queue_data : dev_data->queueMap) {
83386fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        auto event_entry = queue_data.second.eventToStageMap.find(event);
83396fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        if (event_entry != queue_data.second.eventToStageMap.end()) {
83406fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis            event_entry->second |= VK_PIPELINE_STAGE_HOST_BIT;
83416fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        }
83426fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    }
83433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) result = dev_data->dispatch_table.SetEvent(device, event);
83445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
83455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
83465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8347bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
8348bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               VkFence fence) {
834956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
83505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
83513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
8352b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
83539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
83549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
8355651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
83564b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    // First verify that fence is not in use
83573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateFenceForSubmit(dev_data, pFence);
8358651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
83599867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence) {
836093ccd9708dad3ffb58a3fc09a3d61cc5fe1569f8Mark Lobodzinski        SubmitFence(pQueue, pFence, std::max(1u, bindInfoCount));
83614b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    }
8362651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
83631344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) {
83641344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx];
83655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Track objects tied to memory
83661344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.bufferBindCount; j++) {
83671344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pBufferBinds[j].bindCount; k++) {
8368f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pBufferBinds[j].pBinds[k];
8369f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
83709b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(bindInfo.pBufferBinds[j].buffer), kVulkanObjectTypeBuffer))
83713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
83725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
83735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
83741344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageOpaqueBindCount; j++) {
83751344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageOpaqueBinds[j].bindCount; k++) {
8376f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageOpaqueBinds[j].pBinds[k];
8377f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
83789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(bindInfo.pImageOpaqueBinds[j].image), kVulkanObjectTypeImage))
83793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
83805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
83815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
83821344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageBindCount; j++) {
83831344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageBinds[j].bindCount; k++) {
8384f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageBinds[j].pBinds[k];
8385f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                // TODO: This size is broken for non-opaque bindings, need to update to comprehend full sparse binding data
8386f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                VkDeviceSize size = sparse_binding.extent.depth * sparse_binding.extent.height * sparse_binding.extent.width * 4;
8387f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, size},
83889b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(bindInfo.pImageBinds[j].image), kVulkanObjectTypeImage))
83893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
83905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
83915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
83929867daedbf52debc77d6568162ee21e071699b80Chris Forbes
83939867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<SEMAPHORE_WAIT> semaphore_waits;
83949867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<VkSemaphore> semaphore_signals;
83951344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
839601a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pWaitSemaphores[i];
83979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
839801a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
839901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
84009867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
84019867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
84029867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        pSemaphore->in_use.fetch_add(1);
84039867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
84049867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = VK_NULL_HANDLE;
840501a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                    pSemaphore->signaled = false;
84061344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
84073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
84089b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
84093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkQueueBindSparse: Queue 0x%p is waiting on semaphore 0x%" PRIx64
84103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " that has no way to be signaled.",
84119b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    queue, HandleToUint64(semaphore));
84125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
84135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
84145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
84151344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
841601a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pSignalSemaphores[i];
84179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
841801a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
841901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
84203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
84219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                   HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
84223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                   "vkQueueBindSparse: Queue 0x%p is signaling semaphore 0x%" PRIx64
84233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                   ", but that semaphore is already signaled.",
84249b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                   queue, HandleToUint64(semaphore));
8425bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                } else {
84269867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = queue;
84279867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
84289867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaled = true;
84299867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->in_use.fetch_add(1);
84309867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    semaphore_signals.push_back(semaphore);
84319867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
84325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
84335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
84349867daedbf52debc77d6568162ee21e071699b80Chris Forbes
8435bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), semaphore_waits, semaphore_signals,
84369867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         bindIdx == bindInfoCount - 1 ? fence : VK_NULL_HANDLE);
84375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
84389867daedbf52debc77d6568162ee21e071699b80Chris Forbes
84399867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence && !bindInfoCount) {
84409867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // No work to do, just dropping a fence in the queue by itself.
8441bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
84429867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         fence);
84439867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
84449867daedbf52debc77d6568162ee21e071699b80Chris Forbes
8445b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
84465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
84473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) return dev_data->dispatch_table.QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
84485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
84495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
84505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
845289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
845389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
845456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
84554a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
84565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
8457b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
8458bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        SEMAPHORE_NODE *sNode = &dev_data->semaphoreMap[*pSemaphore];
84599867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.first = VK_NULL_HANDLE;
84609867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.second = 0;
84611344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        sNode->signaled = false;
84625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
84635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
84645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8466bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
8467bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
846856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
84694a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateEvent(device, pCreateInfo, pAllocator, pEvent);
84705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
8471b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
84725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].needsSignaled = false;
8473293ecfc5e69ed3978a8c04518166d828294870a4Tony Barbour        dev_data->eventMap[*pEvent].write_in_use = 0;
84745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
84755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
84765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
84775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
84799ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinskistatic bool PreCallValidateCreateSwapchainKHR(layer_data *dev_data, const char *func_name,
84809ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              VkSwapchainCreateInfoKHR const *pCreateInfo, SURFACE_STATE *surface_state,
84819ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              SWAPCHAIN_NODE *old_swapchain_state) {
8482d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    auto most_recent_swapchain = surface_state->swapchain ? surface_state->swapchain : surface_state->old_swapchain;
8483d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
84844bd5f453535de3d3423ff1f9995b4acb15f791d2Chris Forbes    // TODO: revisit this. some of these rules are being relaxed.
84850bbc015828bdb99e85e6731ce92428557902701fPetr Kraus
84860bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    // All physical devices and queue families are required to be able
84870bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    // to present to any native window on Android; require the
84880bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    // application to have established support on any other platform.
8489d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski    if (!dev_data->instance_data->extensions.vk_khr_android_surface) {
84900bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        auto support_predicate = [dev_data](decltype(surface_state->gpu_queue_support)::const_reference qs) -> bool {
84910bbc015828bdb99e85e6731ce92428557902701fPetr Kraus            // TODO: should restrict search only to queue families of VkDeviceQueueCreateInfos, not whole phys. device
84920bbc015828bdb99e85e6731ce92428557902701fPetr Kraus            return (qs.first.gpu == dev_data->physical_device) && qs.second;
84930bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        };
84940bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        const auto& support = surface_state->gpu_queue_support;
84950bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        bool is_supported = std::any_of(support.begin(), support.end(), support_predicate);
84960bbc015828bdb99e85e6731ce92428557902701fPetr Kraus
84970bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        if (!is_supported) {
84980bbc015828bdb99e85e6731ce92428557902701fPetr Kraus            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8499315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009ec, "DS",
85000bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                        "%s: pCreateInfo->surface is not known at this time to be supported for presentation by this device. "
85010bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                        "The vkGetPhysicalDeviceSurfaceSupportKHR() must be called beforehand, and it must return VK_TRUE support "
85020bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                        "with this surface for at least one queue family of this device. %s",
8503315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        func_name, validation_error_map[VALIDATION_ERROR_146009ec]))
85040bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                return true;
85050bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        }
85060bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    }
85070bbc015828bdb99e85e6731ce92428557902701fPetr Kraus
8508d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (most_recent_swapchain != old_swapchain_state || (surface_state->old_swapchain && surface_state->swapchain)) {
8509d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
85109b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_ALREADY_EXISTS, "DS",
85119ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface has an existing swapchain other than oldSwapchain", func_name))
8512d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
8513d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
8514d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (old_swapchain_state && old_swapchain_state->createInfo.surface != pCreateInfo->surface) {
8515d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
85169b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(pCreateInfo->oldSwapchain), __LINE__, DRAWSTATE_SWAPCHAIN_WRONG_SURFACE, "DS",
85179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    "%s: pCreateInfo->oldSwapchain's surface is not pCreateInfo->surface", func_name))
8518d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
8519d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
85209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
85217de258f87ca1192db116a66b209253793d276ebcChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState == UNCALLED) {
85227de258f87ca1192db116a66b209253793d276ebcChris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
85239b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(dev_data->physical_device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
85249ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface capabilities not retrieved for this physical device", func_name))
85257de258f87ca1192db116a66b209253793d276ebcChris Forbes            return true;
8526cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // have valid capabilities
85275c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        auto &capabilities = physical_device_state->surfaceCapabilities;
85289ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->minImageCount against VkSurfaceCapabilitiesKHR::{min|max}ImageCount:
85292fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if (pCreateInfo->minImageCount < capabilities.minImageCount) {
85302fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8531315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009ee, "DS",
85329ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
85332fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
85349ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
8535315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009ee]))
85362fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                return true;
85372fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        }
85382fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
85392fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if ((capabilities.maxImageCount > 0) && (pCreateInfo->minImageCount > capabilities.maxImageCount)) {
85405c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8541315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f0, "DS",
85429ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
85432fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
85449ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
8545315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f0]))
85465c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
85475c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
85482fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
85499ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageExtent against VkSurfaceCapabilitiesKHR::{current|min|max}ImageExtent:
85502e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width == kSurfaceSizeFromSwapchain) &&
85512e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width < capabilities.minImageExtent.width) ||
85522e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.width > capabilities.maxImageExtent.width) ||
85532e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height < capabilities.minImageExtent.height) ||
85542e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height > capabilities.maxImageExtent.height))) {
85555c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8556315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f4, "DS",
85579ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is outside the bounds returned by "
85589ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (%d,%d), minImageExtent = (%d,%d), "
85599ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "maxImageExtent = (%d,%d). %s",
85609ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
85619ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height, capabilities.minImageExtent.width,
85629ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.minImageExtent.height, capabilities.maxImageExtent.width, capabilities.maxImageExtent.height,
8563315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f4]))
85645c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
85655c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
85669ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->preTransform should have exactly one bit set, and that bit must also be set in
85679ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedTransforms.
85685c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->preTransform || (pCreateInfo->preTransform & (pCreateInfo->preTransform - 1)) ||
85695c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !(pCreateInfo->preTransform & capabilities.supportedTransforms)) {
85709ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
85719ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
85725c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
85735c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
85745c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
85759ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->preTransform (i.e. %s).  Supported values are:\n", func_name,
85765c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    string_VkSurfaceTransformFlagBitsKHR(pCreateInfo->preTransform));
85775c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
85785c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
85795c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
85805c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedTransforms) {
85815c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkSurfaceTransformFlagBitsKHR((VkSurfaceTransformFlagBitsKHR)(1 << i));
85825c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
85835c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
85845c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
85855c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
85865c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
85875c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8588315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009fe, "DS", "%s. %s", errorString.c_str(),
8589315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009fe]))
85905c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
85915c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
85927b0d28d116977b91892f354e002edd760bdb86cbChris Forbes
85939ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->compositeAlpha should have exactly one bit set, and that bit must also be set in
85949ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedCompositeAlpha
85955c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->compositeAlpha || (pCreateInfo->compositeAlpha & (pCreateInfo->compositeAlpha - 1)) ||
85965c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !((pCreateInfo->compositeAlpha) & capabilities.supportedCompositeAlpha)) {
85979ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
85989ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
85995c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
86005c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
86015c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
86029ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->compositeAlpha (i.e. %s).  Supported values are:\n",
86039ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    func_name, string_VkCompositeAlphaFlagBitsKHR(pCreateInfo->compositeAlpha));
86045c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
86055c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
86065c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
86075c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedCompositeAlpha) {
86085c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkCompositeAlphaFlagBitsKHR((VkCompositeAlphaFlagBitsKHR)(1 << i));
86095c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
86105c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
86115c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
86125c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
86135c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
86145c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8615315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_14600a00, "DS", "%s. %s", errorString.c_str(),
8616315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_14600a00]))
86175c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
86185c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
86199ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageArrayLayers against VkSurfaceCapabilitiesKHR::maxImageArrayLayers:
86205c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if ((pCreateInfo->imageArrayLayers < 1) || (pCreateInfo->imageArrayLayers > capabilities.maxImageArrayLayers)) {
86215c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8622315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f6, "DS",
86239ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported imageArrayLayers (i.e. %d).  Minimum value is 1, maximum value is %d. %s",
86249ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageArrayLayers, capabilities.maxImageArrayLayers,
8625315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f6]))
86265c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
86275c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
86289ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageUsage against VkSurfaceCapabilitiesKHR::supportedUsageFlags:
86295c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (pCreateInfo->imageUsage != (pCreateInfo->imageUsage & capabilities.supportedUsageFlags)) {
86305c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8631315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f8, "DS",
86329ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported pCreateInfo->imageUsage (i.e. 0x%08x).  Supported flag bits are 0x%08x. %s",
86339ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageUsage, capabilities.supportedUsageFlags,
8634315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f8]))
86355c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
86365c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
86377de258f87ca1192db116a66b209253793d276ebcChris Forbes    }
8638d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
86399ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfaceFormatsKHR():
86405faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState != QUERY_DETAILS) {
86415faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
86429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
86439ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s called before calling vkGetPhysicalDeviceSurfaceFormatsKHR().", func_name))
86445faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            return true;
86455faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    } else {
86469ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageFormat against VkSurfaceFormatKHR::format:
86475faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundFormat = false;
86485faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundColorSpace = false;
86495faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundMatch = false;
86505faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        for (auto const &format : physical_device_state->surface_formats) {
86515faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (pCreateInfo->imageFormat == format.format) {
86529ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                // Validate pCreateInfo->imageColorSpace against VkSurfaceFormatKHR::colorSpace:
86535faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                foundFormat = true;
86545faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
86555faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundMatch = true;
86565faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    break;
86575faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
86585faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            } else {
86595faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
86605faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundColorSpace = true;
86615faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
86625faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
86635faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
86645faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (!foundMatch) {
86655faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (!foundFormat) {
86665faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8667315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f2, "DS",
8668bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageFormat (i.e. %d). %s", func_name,
8669315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCreateInfo->imageFormat, validation_error_map[VALIDATION_ERROR_146009f2]))
86702fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                    return true;
86712fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            }
86722fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (!foundColorSpace) {
86732fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8674315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f2, "DS",
8675bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageColorSpace (i.e. %d). %s", func_name,
8676315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCreateInfo->imageColorSpace, validation_error_map[VALIDATION_ERROR_146009f2]))
86775faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    return true;
86785faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
86795faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
86805faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
86815faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
86829ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfacePresentModesKHR():
86839e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState != QUERY_DETAILS) {
868425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // FIFO is required to always be supported
86859e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pCreateInfo->presentMode != VK_PRESENT_MODE_FIFO_KHR) {
86869e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
86879b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
86889ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called before calling vkGetPhysicalDeviceSurfacePresentModesKHR().", func_name))
86899e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
86909e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
86919e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    } else {
86929ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->presentMode against vkGetPhysicalDeviceSurfacePresentModesKHR():
8693bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        bool foundMatch = std::find(physical_device_state->present_modes.begin(), physical_device_state->present_modes.end(),
86949e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                    pCreateInfo->presentMode) != physical_device_state->present_modes.end();
86959e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (!foundMatch) {
86969e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8697315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_14600a02, "DS",
86989ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported presentMode (i.e. %s). %s", func_name,
8699315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        string_VkPresentModeKHR(pCreateInfo->presentMode), validation_error_map[VALIDATION_ERROR_14600a02]))
87009e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
87019e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
87029e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
870387a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis    // Validate state for shared presentable case
870487a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis    if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfo->presentMode ||
870587a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfo->presentMode) {
8706a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski        if (!dev_data->extensions.vk_khr_shared_presentable_image) {
870787a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8708480a11822ef9a45f577f13644759c0895a49db19Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_EXTENSION_NOT_ENABLED, "DS",
87096084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        "%s called with presentMode %s which requires the VK_KHR_shared_presentable_image extension, which has not "
87106084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        "been enabled.",
87116084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        func_name, string_VkPresentModeKHR(pCreateInfo->presentMode)))
87126084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                return true;
87136084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski        } else if (pCreateInfo->minImageCount != 1) {
87146084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8715315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_14600ace, "DS",
871687a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                        "%s called with presentMode %s, but minImageCount value is %d. For shared presentable image, minImageCount "
87176084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        "must be 1. %s",
87186084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        func_name, string_VkPresentModeKHR(pCreateInfo->presentMode), pCreateInfo->minImageCount,
8719315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_14600ace]))
872087a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                return true;
872187a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        }
872287a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis    }
87239e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
8724d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    return false;
8725d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes}
8726d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
8727261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinskistatic void PostCallRecordCreateSwapchainKHR(layer_data *dev_data, VkResult result, const VkSwapchainCreateInfoKHR *pCreateInfo,
8728261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             VkSwapchainKHR *pSwapchain, SURFACE_STATE *surface_state,
8729261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             SWAPCHAIN_NODE *old_swapchain_state) {
87305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
8731b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
8732ddc5201048319558ce66701163a4546ee957af19Chris Forbes        auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(pCreateInfo, *pSwapchain));
873387a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfo->presentMode ||
873487a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfo->presentMode) {
873587a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            swapchain_state->shared_presentable = true;
873687a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        }
8737ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = swapchain_state.get();
873816a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes        dev_data->swapchainMap[*pSwapchain] = std::move(swapchain_state);
8739ddc5201048319558ce66701163a4546ee957af19Chris Forbes    } else {
8740ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = nullptr;
87415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8742ddc5201048319558ce66701163a4546ee957af19Chris Forbes    // Spec requires that even if CreateSwapchainKHR fails, oldSwapchain behaves as replaced.
87435b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    if (old_swapchain_state) {
87445b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes        old_swapchain_state->replaced = true;
87455b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    }
8746ddc5201048319558ce66701163a4546ee957af19Chris Forbes    surface_state->old_swapchain = old_swapchain_state;
8747261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    return;
8748261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski}
8749261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
8750261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
8751261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
875256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
87539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(dev_data->instance_data, pCreateInfo->surface);
87549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto old_swapchain_state = GetSwapchainNode(dev_data, pCreateInfo->oldSwapchain);
8755261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
87569ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    if (PreCallValidateCreateSwapchainKHR(dev_data, "vkCreateSwapChainKHR()", pCreateInfo, surface_state, old_swapchain_state)) {
8757261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
8758261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    }
8759261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
8760261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    VkResult result = dev_data->dispatch_table.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
8761261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
8762261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    PostCallRecordCreateSwapchainKHR(dev_data, result, pCreateInfo, pSwapchain, surface_state, old_swapchain_state);
8763ddc5201048319558ce66701163a4546ee957af19Chris Forbes
87645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
87655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8767bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
876856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
87693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
87705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8771b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
87729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
8773b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swapchain_data) {
8774b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_data->images.size() > 0) {
8775b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis            for (auto swapchain_image : swapchain_data->images) {
87765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
87775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (image_sub != dev_data->imageSubresourceMap.end()) {
87785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    for (auto imgsubpair : image_sub->second) {
87795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
87805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if (image_item != dev_data->imageLayoutMap.end()) {
87815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            dev_data->imageLayoutMap.erase(image_item);
87825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
87835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
87845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    dev_data->imageSubresourceMap.erase(image_sub);
87855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
87869b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip = ClearMemoryObjectBindings(dev_data, HandleToUint64(swapchain_image), kVulkanObjectTypeSwapchainKHR);
878794c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                dev_data->imageMap.erase(swapchain_image);
87885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
87895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8790ddc5201048319558ce66701163a4546ee957af19Chris Forbes
87919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
8792ddc5201048319558ce66701163a4546ee957af19Chris Forbes        if (surface_state) {
8793cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->swapchain == swapchain_data) surface_state->swapchain = nullptr;
8794cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->old_swapchain == swapchain_data) surface_state->old_swapchain = nullptr;
8795ddc5201048319558ce66701163a4546ee957af19Chris Forbes        }
8796ddc5201048319558ce66701163a4546ee957af19Chris Forbes
879716a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes        dev_data->swapchainMap.erase(swapchain);
87985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8799b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
88003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
88015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
88025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8803991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinskistatic bool PreCallValidateGetSwapchainImagesKHR(layer_data *device_data, SWAPCHAIN_NODE *swapchain_state, VkDevice device,
8804991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                 uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) {
8805991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    bool skip = false;
8806991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if (swapchain_state && pSwapchainImages) {
8807b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
8808991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        // Compare the preliminary value of *pSwapchainImageCount with the value this time:
8809991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        if (swapchain_state->vkGetSwapchainImagesKHRState == UNCALLED) {
8810991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8811991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                            HandleToUint64(device), __LINE__, SWAPCHAIN_PRIOR_COUNT, "DS",
8812991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                            "vkGetSwapchainImagesKHR() called with non-NULL pSwapchainImageCount; but no prior positive "
8813991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                            "value has been seen for pSwapchainImages.");
8814991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        } else if (*pSwapchainImageCount > swapchain_state->get_swapchain_image_count) {
8815991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
8816991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                            HandleToUint64(device), __LINE__, SWAPCHAIN_INVALID_COUNT, "DS",
8817991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                            "vkGetSwapchainImagesKHR() called with non-NULL pSwapchainImageCount, and with "
8818991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                            "pSwapchainImages set to a value (%d) that is greater than the value (%d) that was returned when "
8819991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                            "pSwapchainImageCount was NULL.",
8820991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                            *pSwapchainImageCount, swapchain_state->get_swapchain_image_count);
8821991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        }
8822991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    }
8823991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    return skip;
8824991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski}
8825991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
8826991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinskistatic void PostCallRecordGetSwapchainImagesKHR(layer_data *device_data, SWAPCHAIN_NODE *swapchain_state, VkDevice device,
8827991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) {
8828991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
8829ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes
8830991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if (*pSwapchainImageCount > swapchain_state->images.size()) swapchain_state->images.resize(*pSwapchainImageCount);
8831ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes
8832991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if (pSwapchainImages) {
8833991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        if (swapchain_state->vkGetSwapchainImagesKHRState < QUERY_DETAILS) {
8834991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            swapchain_state->vkGetSwapchainImagesKHRState = QUERY_DETAILS;
8835991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        }
8836991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        for (uint32_t i = 0; i < *pSwapchainImageCount; ++i) {
8837991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            if (swapchain_state->images[i] != VK_NULL_HANDLE) continue;  // Already retrieved this.
8838ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes
88395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            IMAGE_LAYOUT_NODE image_layout_node;
88405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
8841991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            image_layout_node.format = swapchain_state->createInfo.imageFormat;
88426d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            // Add imageMap entries for each swapchain image
88436d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            VkImageCreateInfo image_ci = {};
8844eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.flags = 0;
8845eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.imageType = VK_IMAGE_TYPE_2D;
8846991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            image_ci.format = swapchain_state->createInfo.imageFormat;
8847991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            image_ci.extent.width = swapchain_state->createInfo.imageExtent.width;
8848991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            image_ci.extent.height = swapchain_state->createInfo.imageExtent.height;
8849d1a9776c1a22ec99a3ef0dd44e7f85a78a04d1edTony Barbour            image_ci.extent.depth = 1;
8850eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.mipLevels = 1;
8851991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            image_ci.arrayLayers = swapchain_state->createInfo.imageArrayLayers;
8852eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
8853eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
8854991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            image_ci.usage = swapchain_state->createInfo.imageUsage;
8855991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            image_ci.sharingMode = swapchain_state->createInfo.imageSharingMode;
8856991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            device_data->imageMap[pSwapchainImages[i]] = unique_ptr<IMAGE_STATE>(new IMAGE_STATE(pSwapchainImages[i], &image_ci));
8857991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            auto &image_state = device_data->imageMap[pSwapchainImages[i]];
88581facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->valid = false;
8859e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            image_state->binding.mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
8860991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            swapchain_state->images[i] = pSwapchainImages[i];
88615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
8862991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            device_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
8863991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            device_data->imageLayoutMap[subpair] = image_layout_node;
88645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
88655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8866991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
8867991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if (*pSwapchainImageCount) {
8868991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        if (swapchain_state->vkGetSwapchainImagesKHRState < QUERY_COUNT) {
8869991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            swapchain_state->vkGetSwapchainImagesKHRState = QUERY_COUNT;
8870991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        }
8871991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        swapchain_state->get_swapchain_image_count = *pSwapchainImageCount;
8872991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    }
8873991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski}
8874991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
8875991f2555bc4f571e30b584937c7959805dff67c6Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
8876991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                     VkImage *pSwapchainImages) {
8877991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
8878991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
8879991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
8880991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    auto swapchain_state = GetSwapchainNode(device_data, swapchain);
8881991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    bool skip = PreCallValidateGetSwapchainImagesKHR(device_data, swapchain_state, device, pSwapchainImageCount, pSwapchainImages);
8882991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
8883991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if (!skip) {
8884991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        result = device_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
8885991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    }
8886991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
8887991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if ((result == VK_SUCCESS || result == VK_INCOMPLETE)) {
8888991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        PostCallRecordGetSwapchainImagesKHR(device_data, swapchain_state, device, pSwapchainImageCount, pSwapchainImages);
8889991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    }
88905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
88915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
88925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
889389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
889456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
88953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
88965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
88976c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    std::lock_guard<std::mutex> lock(global_lock);
88989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
88991671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
89006c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
89019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
89026c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        if (pSemaphore && !pSemaphore->signaled) {
89033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
89043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
89053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
89069b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPresentInfo->pWaitSemaphores[i]));
89075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89086c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
8909249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
89106c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
89119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
8912a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes        if (swapchain_data) {
8913a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes            if (pPresentInfo->pImageIndices[i] >= swapchain_data->images.size()) {
89149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |=
89159b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
89169b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
89179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "vkQueuePresentKHR: Swapchain image index too large (%u). There are only %u images in this swapchain.",
89189b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pPresentInfo->pImageIndices[i], (uint32_t)swapchain_data->images.size());
8919bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            } else {
8920a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
89219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, image);
892287a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis
892387a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                if (image_state->shared_presentable) {
892487a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                    image_state->layout_locked = true;
892587a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                }
8926c4f799ed5502f05ce97543e0500b4a19dc5f2461Mark Lobodzinski
89273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateImageMemoryIsValid(dev_data, image_state, "vkQueuePresentKHR()");
8928a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
89291facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                if (!image_state->acquired) {
89303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
8931bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
89329b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_IMAGE_NOT_ACQUIRED, "DS",
8933bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        "vkQueuePresentKHR: Swapchain image index %u has not been acquired.", pPresentInfo->pImageIndices[i]);
8934a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                }
8935a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
8936a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                vector<VkImageLayout> layouts;
8937a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                if (FindLayouts(dev_data, image, layouts)) {
8938a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                    for (auto layout : layouts) {
89396084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        if ((layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) &&
8940a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski                            (!dev_data->extensions.vk_khr_shared_presentable_image ||
89416084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                             (layout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR))) {
89423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |=
89432fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
8944315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        HandleToUint64(queue), __LINE__, VALIDATION_ERROR_11200a20, "DS",
89452fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "Images passed to present must be in layout "
89466084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                                        "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR or VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR but is in %s. %s",
8947315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        string_VkImageLayout(layout), validation_error_map[VALIDATION_ERROR_11200a20]);
8948a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        }
89495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
89505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
89515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
89521671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
89531671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // All physical devices and queue families are required to be able
89541671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // to present to any native window on Android; require the
89551671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // application to have established support on any other platform.
8956d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski            if (!dev_data->instance_data->extensions.vk_khr_android_surface) {
89579a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
89581671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                auto support_it = surface_state->gpu_queue_support.find({dev_data->physical_device, queue_state->queueFamilyIndex});
89591671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
89601671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                if (support_it == surface_state->gpu_queue_support.end()) {
89613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |=
89621671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
89639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_UNSUPPORTED_QUEUE, "DS",
8964cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkQueuePresentKHR: Presenting image without calling "
8965cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkGetPhysicalDeviceSurfaceSupportKHR");
89661671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                } else if (!support_it->second) {
89679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    skip |=
89689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
8969315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, VALIDATION_ERROR_31800a18, "DS",
89709b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkQueuePresentKHR: Presenting image on queue that cannot "
89719b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "present to this surface. %s",
8972315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_31800a18]);
89731671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                }
89741671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            }
89755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8977c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis    if (pPresentInfo && pPresentInfo->pNext) {
8978c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        // Verify ext struct
8979c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        struct std_header {
8980c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            VkStructureType sType;
8981c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            const void *pNext;
8982c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        };
8983c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        std_header *pnext = (std_header *)pPresentInfo->pNext;
8984c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        while (pnext) {
8985c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            if (VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR == pnext->sType) {
8986c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                VkPresentRegionsKHR *present_regions = (VkPresentRegionsKHR *)pnext;
8987c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
8988c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
8989c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    assert(swapchain_data);
8990c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    VkPresentRegionKHR region = present_regions->pRegions[i];
8991c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    for (uint32_t j = 0; j < region.rectangleCount; ++j) {
8992c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        VkRectLayerKHR rect = region.pRectangles[j];
8993c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        // TODO: Need to update these errors to their unique error ids when available
8994c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if ((rect.offset.x + rect.extent.width) > swapchain_data->createInfo.imageExtent.width) {
89959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            skip |= log_msg(
89969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
89979b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
89989b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
89999b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "chain, pRegion[%i].pRectangles[%i], the sum of offset.x "
90009b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "(%i) and extent.width (%i) is greater than the "
90019b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "corresponding swapchain's imageExtent.width (%i).",
90029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                i, j, rect.offset.x, rect.extent.width, swapchain_data->createInfo.imageExtent.width);
9003c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
9004c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if ((rect.offset.y + rect.extent.height) > swapchain_data->createInfo.imageExtent.height) {
90059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            skip |= log_msg(
90069b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
90079b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
90089b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
90099b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "chain, pRegion[%i].pRectangles[%i], the sum of offset.y "
90109b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "(%i) and extent.height (%i) is greater than the "
90119b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "corresponding swapchain's imageExtent.height (%i).",
90129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                i, j, rect.offset.y, rect.extent.height, swapchain_data->createInfo.imageExtent.height);
9013c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
9014c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if (rect.layer > swapchain_data->createInfo.imageArrayLayers) {
90153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |= log_msg(
9016c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
90179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
9018c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, pRegion[%i].pRectangles[%i], the "
9019c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                "layer (%i) is greater than the corresponding swapchain's imageArrayLayers (%i).",
9020c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                i, j, rect.layer, swapchain_data->createInfo.imageArrayLayers);
9021c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
9022c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    }
9023c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                }
90245f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis            } else if (VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE == pnext->sType) {
90255f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                VkPresentTimesInfoGOOGLE *present_times_info = (VkPresentTimesInfoGOOGLE *)pnext;
90265f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                if (pPresentInfo->swapchainCount != present_times_info->swapchainCount) {
90275f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                    skip |=
90285f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
90299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[0]), __LINE__,
90305f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis
9031315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                VALIDATION_ERROR_118009be, "DS",
90325f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "vkQueuePresentKHR(): VkPresentTimesInfoGOOGLE.swapchainCount is %i but "
90335f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "pPresentInfo->swapchainCount is %i. For VkPresentTimesInfoGOOGLE down pNext "
90345f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "chain of VkPresentInfoKHR, VkPresentTimesInfoGOOGLE.swapchainCount "
90355f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "must equal VkPresentInfoKHR.swapchainCount.",
90365f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                present_times_info->swapchainCount, pPresentInfo->swapchainCount);
90375f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                }
9038c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            }
9039c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            pnext = (std_header *)pnext->pNext;
9040c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        }
9041c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis    }
90425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
90433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
90446c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
90456c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
90466c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
90474a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueuePresentKHR(queue, pPresentInfo);
90486c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
90496c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (result != VK_ERROR_VALIDATION_FAILED_EXT) {
90506c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // Semaphore waits occur before error generation, if the call reached
90516c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // the ICD. (Confirm?)
90526c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
90539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
90549867daedbf52debc77d6568162ee21e071699b80Chris Forbes            if (pSemaphore) {
90559867daedbf52debc77d6568162ee21e071699b80Chris Forbes                pSemaphore->signaler.first = VK_NULL_HANDLE;
90566c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes                pSemaphore->signaled = false;
90576c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes            }
90586c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        }
90599867daedbf52debc77d6568162ee21e071699b80Chris Forbes
9060220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
9061220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Note: this is imperfect, in that we can get confused about what
9062220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // did or didn't succeed-- but if the app does that, it's confused
9063220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // itself just as much.
9064220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto local_result = pPresentInfo->pResults ? pPresentInfo->pResults[i] : result;
9065220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
9066cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (local_result != VK_SUCCESS && local_result != VK_SUBOPTIMAL_KHR) continue;  // this present didn't actually happen.
9067220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
9068220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Mark the image as having been released to the WSI
90699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
9070220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
90719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_state = GetImageState(dev_data, image);
90721facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->acquired = false;
9073220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        }
9074220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
90759867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // Note: even though presentation is directed to a queue, there is no
90769867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // direct ordering between QP and subsequent work, so QP (and its
90779867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // semaphore waits) /never/ participate in any completion proof.
90786c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
90791344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
90805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
90815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9083c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic bool PreCallValidateCreateSharedSwapchainsKHR(layer_data *dev_data, uint32_t swapchainCount,
9084c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
9085c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SURFACE_STATE *> &surface_state,
9086c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
90870342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (pCreateInfos) {
9088c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
90890342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
90909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            surface_state.push_back(GetSurfaceState(dev_data->instance_data, pCreateInfos[i].surface));
90919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            old_swapchain_state.push_back(GetSwapchainNode(dev_data, pCreateInfos[i].oldSwapchain));
90929ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            std::stringstream func_name;
90939ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            func_name << "vkCreateSharedSwapchainsKHR[" << swapchainCount << "]";
9094bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (PreCallValidateCreateSwapchainKHR(dev_data, func_name.str().c_str(), &pCreateInfos[i], surface_state[i],
9095bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  old_swapchain_state[i])) {
9096c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                return true;
90970342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            }
90980342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
90990342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
9100c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return false;
9101c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
91020342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
9103c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic void PostCallRecordCreateSharedSwapchainsKHR(layer_data *dev_data, VkResult result, uint32_t swapchainCount,
9104c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
9105c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SURFACE_STATE *> &surface_state,
9106c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
91070342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (VK_SUCCESS == result) {
91080342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
91090342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(&pCreateInfos[i], pSwapchains[i]));
911087a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfos[i].presentMode ||
911187a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfos[i].presentMode) {
911287a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                swapchain_state->shared_presentable = true;
911387a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            }
91140342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = swapchain_state.get();
911516a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes            dev_data->swapchainMap[pSwapchains[i]] = std::move(swapchain_state);
91160342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
91170342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    } else {
91180342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
91190342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = nullptr;
91200342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
91210342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
91220342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    // Spec requires that even if CreateSharedSwapchainKHR fails, oldSwapchain behaves as replaced.
91230342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    for (uint32_t i = 0; i < swapchainCount; i++) {
91240342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        if (old_swapchain_state[i]) {
91250342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            old_swapchain_state[i]->replaced = true;
91260342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
91270342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        surface_state[i]->old_swapchain = old_swapchain_state[i];
91280342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
9129c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return;
9130c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
9131c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
9132c6cd632d064579a64e61d8704b411d0e4ace7adaMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
9133c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkSwapchainCreateInfoKHR *pCreateInfos,
9134c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
913556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
9136c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SURFACE_STATE *> surface_state;
9137c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SWAPCHAIN_NODE *> old_swapchain_state;
9138c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
9139c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    if (PreCallValidateCreateSharedSwapchainsKHR(dev_data, swapchainCount, pCreateInfos, pSwapchains, surface_state,
9140c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                 old_swapchain_state)) {
9141c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
9142c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    }
9143c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
9144c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    VkResult result =
9145c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        dev_data->dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
9146c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
9147c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    PostCallRecordCreateSharedSwapchainsKHR(dev_data, result, swapchainCount, pCreateInfos, pSwapchains, surface_state,
9148c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                            old_swapchain_state);
91490342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
9150c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    return result;
9151c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young}
9152c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
915389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
915489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
915556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
91563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
91571344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
9158b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
9159449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
9160449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    if (fence == VK_NULL_HANDLE && semaphore == VK_NULL_HANDLE) {
91613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
91629b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(device), __LINE__, DRAWSTATE_SWAPCHAIN_NO_SYNC_FOR_ACQUIRE, "DS",
91633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: Semaphore and fence cannot both be VK_NULL_HANDLE. There would be no way "
91643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "to determine the completion of this operation.");
9165449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    }
9166449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
91679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
9168f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pSemaphore && pSemaphore->signaled) {
91693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
9170315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(semaphore), __LINE__, VALIDATION_ERROR_16400a0c, "DS",
91713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state. %s",
9172315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_16400a0c]);
91735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9174f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
91759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
9176f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pFence) {
91773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateFenceForSubmit(dev_data, pFence);
91785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91794a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes
91809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
9181fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
9182fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    if (swapchain_data->replaced) {
91833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
91849b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_REPLACED, "DS",
91853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: This swapchain has been replaced. The application can still "
91863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "present any images it has acquired, but cannot acquire any more.");
9187fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    }
9188fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
91899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
91904a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState != UNCALLED) {
91916569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        uint64_t acquired_images = std::count_if(swapchain_data->images.begin(), swapchain_data->images.end(),
91929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                 [=](VkImage image) { return GetImageState(dev_data, image)->acquired; });
91934a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        if (acquired_images > swapchain_data->images.size() - physical_device_state->surfaceCapabilities.minImageCount) {
91943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
91956569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
91969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_TOO_MANY_IMAGES, "DS",
91976569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        "vkAcquireNextImageKHR: Application has already acquired the maximum number of images (0x%" PRIxLEAST64 ")",
91986569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        acquired_images);
91994a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        }
92004a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    }
920175269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
920275269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    if (swapchain_data->images.size() == 0) {
92033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
92049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_IMAGES_NOT_FOUND, "DS",
92053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: No images found to acquire from. Application probably did not call "
92063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkGetSwapchainImagesKHR after swapchain creation.");
920775269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    }
920875269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
9209b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
92101344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
92113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
9212f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
92134a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
9214f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
9215f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.lock();
9216f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
9217f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pFence) {
9218f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pFence->state = FENCE_INFLIGHT;
9219cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            pFence->signaler.first = VK_NULL_HANDLE;  // ANI isn't on a queue, so this can't participate in a completion proof.
9220f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
9221f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
9222f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        // A successful call to AcquireNextImageKHR counts as a signal operation on semaphore
9223f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pSemaphore) {
9224f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pSemaphore->signaled = true;
92259867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pSemaphore->signaler.first = VK_NULL_HANDLE;
9226f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
9227220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
9228220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        // Mark the image as acquired.
9229220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        auto image = swapchain_data->images[*pImageIndex];
92309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, image);
92311facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->acquired = true;
923287a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        image_state->shared_presentable = swapchain_data->shared_presentable;
92335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9234f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.unlock();
92351344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
92365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
92375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
92385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9239f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
9240f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski                                                        VkPhysicalDevice *pPhysicalDevices) {
92413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
924256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
9243bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    assert(instance_data);
9244219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
9245bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    // For this instance, flag when vkEnumeratePhysicalDevices goes to QUERY_COUNT and then QUERY_DETAILS
9246bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
9247bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_COUNT;
9248f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    } else {
9249bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        if (UNCALLED == instance_data->vkEnumeratePhysicalDevicesState) {
9250bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Flag warning here. You can call this without having queried the count, but it may not be
9251bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // robust on platforms with multiple physical devices.
92523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
92533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
92543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call sequence has vkEnumeratePhysicalDevices() w/ non-NULL pPhysicalDevices. You should first "
92553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "call vkEnumeratePhysicalDevices() w/ NULL pPhysicalDevices to query pPhysicalDeviceCount.");
9256cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }  // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
9257bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        else if (instance_data->physical_devices_count != *pPhysicalDeviceCount) {
9258bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Having actual count match count from app is not a requirement, so this can be a warning
92593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
92603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
92613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call to vkEnumeratePhysicalDevices() w/ pPhysicalDeviceCount value %u, but actual count "
92623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "supported by this instance is %u.",
92633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            *pPhysicalDeviceCount, instance_data->physical_devices_count);
9264bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
9265bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_DETAILS;
9266f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
92673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
9268bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
9269bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
9270bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    VkResult result = instance_data->dispatch_table.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
9271bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
9272bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->physical_devices_count = *pPhysicalDeviceCount;
9273cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (result == VK_SUCCESS) {  // Save physical devices
9274bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
9275bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            auto &phys_device_state = instance_data->physical_device_map[pPhysicalDevices[i]];
9276bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            phys_device_state.phys_device = pPhysicalDevices[i];
9277bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Init actual features for each physical device
9278bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            instance_data->dispatch_table.GetPhysicalDeviceFeatures(pPhysicalDevices[i], &phys_device_state.features);
9279bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
9280bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
9281bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    return result;
9282f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
9283f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
928443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to handle validation for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
928543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
928643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 PHYSICAL_DEVICE_STATE *pd_state,
92875770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                 uint32_t requested_queue_family_property_count, bool qfp_null,
92885770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                 const char *caller_name) {
928943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = false;
92905770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (!qfp_null) {
92915770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        // Verify that for each physical device, this command is called first with NULL pQueueFamilyProperties in order to get count
929243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
92935770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            skip |= log_msg(
92945770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
92959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(pd_state->phys_device), __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
92965770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "%s is called with non-NULL pQueueFamilyProperties before obtaining pQueueFamilyPropertyCount. It is recommended "
92975770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "to first call %s with NULL pQueueFamilyProperties in order to obtain the maximal pQueueFamilyPropertyCount.",
92985770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                caller_name, caller_name);
92995770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            // Then verify that pCount that is passed in on second call matches what was returned
93005770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        } else if (pd_state->queue_family_count != requested_queue_family_property_count) {
93015770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            skip |= log_msg(
93025770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
93039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(pd_state->phys_device), __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
93045770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "%s is called with non-NULL pQueueFamilyProperties and pQueueFamilyPropertyCount value %" PRIu32
93055770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                ", but the largest previously returned pQueueFamilyPropertyCount for this physicalDevice is %" PRIu32
93065770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                ". It is recommended to instead receive all the properties by calling %s with pQueueFamilyPropertyCount that was "
93075770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "previously obtained by calling %s with NULL pQueueFamilyProperties.",
93085770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                caller_name, requested_queue_family_property_count, pd_state->queue_family_count, caller_name, caller_name);
930943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
931043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_DETAILS;
931143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
93125770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
931343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return skip;
931443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
931543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
931643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
93175770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                  PHYSICAL_DEVICE_STATE *pd_state,
93185770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                  uint32_t *pQueueFamilyPropertyCount,
931943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
93205770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, *pQueueFamilyPropertyCount,
93215770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                (nullptr == pQueueFamilyProperties),
932243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties()");
932343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
932443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
932543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_layer_data *instance_data,
932643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      PHYSICAL_DEVICE_STATE *pd_state,
932743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
932843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
93295770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, *pQueueFamilyPropertyCount,
93305770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                (nullptr == pQueueFamilyProperties),
933143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties2KHR()");
933243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
933343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
933443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to update state for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
933543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
933643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                    VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
933743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (!pQueueFamilyProperties) {
93385770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        if (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState)
93395770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_COUNT;
93405770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->queue_family_count = count;
934143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } else {  // Save queue family properties
93425770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_DETAILS;
93435770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->queue_family_count = std::max(pd_state->queue_family_count, count);
93445770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
93455770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->queue_family_properties.resize(std::max(static_cast<uint32_t>(pd_state->queue_family_properties.size()), count));
93465770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        for (uint32_t i = 0; i < count; ++i) {
934743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            pd_state->queue_family_properties[i] = pQueueFamilyProperties[i].queueFamilyProperties;
934843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
934943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
935043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
935143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
935243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
935343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 VkQueueFamilyProperties *pQueueFamilyProperties) {
935443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    VkQueueFamilyProperties2KHR *pqfp = nullptr;
935543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    std::vector<VkQueueFamilyProperties2KHR> qfp;
935643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    qfp.resize(count);
935743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (pQueueFamilyProperties) {
935843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        for (uint32_t i = 0; i < count; ++i) {
935943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
936043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].pNext = nullptr;
936143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].queueFamilyProperties = pQueueFamilyProperties[i];
936243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
936343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pqfp = qfp.data();
936443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
936543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pqfp);
936643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
936743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
936843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
936943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                     VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
937043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pQueueFamilyProperties);
937143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
937243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
93735770f8ad21c40b2475201e73e9368a899b6886d0Petr KrausVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
93745770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                  uint32_t *pQueueFamilyPropertyCount,
9375bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
937656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
93779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
937843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
93795770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::unique_lock<std::mutex> lock(global_lock);
93805770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
93815770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_data, physical_device_state,
93825770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                      pQueueFamilyPropertyCount, pQueueFamilyProperties);
93835770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
93845770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.unlock();
93855770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
93865770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (skip) return;
93875770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
93885770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount,
93895770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                         pQueueFamilyProperties);
93905770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
93915770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.lock();
93925770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    PostCallRecordGetPhysicalDeviceQueueFamilyProperties(physical_device_state, *pQueueFamilyPropertyCount, pQueueFamilyProperties);
939343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
939443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
939543947a6175e3e942e04d902f4d18928168e2d0dbTobin EhlisVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
939643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
939743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
939856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
93999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
940043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
94015770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::unique_lock<std::mutex> lock(global_lock);
94025770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
940343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_data, physical_device_state,
940443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                          pQueueFamilyPropertyCount, pQueueFamilyProperties);
94055770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
94065770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.unlock();
94075770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
94085770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (skip) return;
94095770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
941043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount,
941143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                             pQueueFamilyProperties);
94125770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
94135770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.lock();
941443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(physical_device_state, *pQueueFamilyPropertyCount,
941543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                             pQueueFamilyProperties);
9416cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski}
9417cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski
9418bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskitemplate <typename TCreateInfo, typename FPtr>
9419bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkResult CreateSurface(VkInstance instance, TCreateInfo const *pCreateInfo, VkAllocationCallbacks const *pAllocator,
9420bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                              VkSurfaceKHR *pSurface, FPtr fptr) {
942156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
9422747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
9423747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    // Call down the call chain:
9424747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    VkResult result = (instance_data->dispatch_table.*fptr)(instance, pCreateInfo, pAllocator, pSurface);
9425747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
9426747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (result == VK_SUCCESS) {
9427747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        std::unique_lock<std::mutex> lock(global_lock);
9428747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map[*pSurface] = SURFACE_STATE(*pSurface);
9429747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        lock.unlock();
9430747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
9431747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
9432747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return result;
9433747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
9434747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
9435747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {
94363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
943756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
9438747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
94399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
9440747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
9441991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if ((surface_state) && (surface_state->swapchain)) {
9442991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
9443991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            HandleToUint64(instance), __LINE__, VALIDATION_ERROR_26c009e4, "DS",
9444991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            "vkDestroySurfaceKHR() called before its associated VkSwapchainKHR was destroyed. %s",
9445991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            validation_error_map[VALIDATION_ERROR_26c009e4]);
9446747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
9447991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    instance_data->surface_map.erase(surface);
9448747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    lock.unlock();
94493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
9450747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->dispatch_table.DestroySurfaceKHR(instance, surface, pAllocator);
9451747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
9452747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
9453747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
94546f2ed666809272002a31b3b4f8adf6581cb41819Norbert NopperVKAPI_ATTR VkResult VKAPI_CALL CreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
94556f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper                                                            const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
94566f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateDisplayPlaneSurfaceKHR);
94576f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper}
94586f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper
9459747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
9460747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo,
9461747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
9462747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateAndroidSurfaceKHR);
9463747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
9464cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
9465747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
9466747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
9467747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateMirSurfaceKHR(VkInstance instance, const VkMirSurfaceCreateInfoKHR *pCreateInfo,
9468747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
9469747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateMirSurfaceKHR);
9470747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
9471f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9472f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceMirPresentationSupportKHR(VkPhysicalDevice physicalDevice,
9473f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                          uint32_t queueFamilyIndex, MirConnection *connection) {
9474f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
9475f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
9476f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9477f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
9478f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
9479f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9480315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2d2009e2,
9481f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceMirPresentationSupportKHR", "queueFamilyIndex");
9482f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9483f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
9484f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9485f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
9486f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9487f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
9488f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result =
9489f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        instance_data->dispatch_table.GetPhysicalDeviceMirPresentationSupportKHR(physicalDevice, queueFamilyIndex, connection);
9490f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9491f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
9492f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
9493cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
9494747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
9495747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
9496747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
9497747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
9498a9c6cc532ce0ef61d48d1419a96aae51b0e4c64aTobin Ehlis    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWaylandSurfaceKHR);
9499747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
9500f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9501f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice,
9502f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                              uint32_t queueFamilyIndex,
9503f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                              struct wl_display *display) {
9504f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
9505f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
9506f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9507f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
9508f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
9509f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9510315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f000a34,
9511f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceWaylandPresentationSupportKHR", "queueFamilyIndex");
9512f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9513f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
9514f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9515f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
9516f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9517f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
9518f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result =
9519f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        instance_data->dispatch_table.GetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, display);
9520f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9521f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
9522f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
9523cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
9524747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
9525747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
9526747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
9527747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
9528747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWin32SurfaceKHR);
9529747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
9530f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9531f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,
9532f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                            uint32_t queueFamilyIndex) {
9533f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
9534f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
9535f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9536f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
9537f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
9538f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9539315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f200a3a,
9540f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceWin32PresentationSupportKHR", "queueFamilyIndex");
9541f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9542f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
9543f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9544f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
9545f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9546f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
9547f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result = instance_data->dispatch_table.GetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
9548f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9549f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
9550f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
9551cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
9552747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
9553747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
9554747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
9555747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
9556747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXcbSurfaceKHR);
9557747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
9558f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9559f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice,
9560f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                          uint32_t queueFamilyIndex, xcb_connection_t *connection,
9561f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                          xcb_visualid_t visual_id) {
9562f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
9563f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
9564f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9565f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
9566f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
9567f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9568315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f400a40,
9569f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceXcbPresentationSupportKHR", "queueFamilyIndex");
9570f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9571f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
9572f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9573f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
9574f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9575f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
9576f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result = instance_data->dispatch_table.GetPhysicalDeviceXcbPresentationSupportKHR(physicalDevice, queueFamilyIndex,
9577f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                                               connection, visual_id);
9578f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9579f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
9580f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
9581cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
9582747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
9583747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
9584747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
9585bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
9586747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXlibSurfaceKHR);
9587747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
9588f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9589f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice,
9590f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                           uint32_t queueFamilyIndex, Display *dpy,
9591f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                           VisualID visualID) {
9592f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
9593f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
9594f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9595f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
9596f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
9597f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9598315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f600a46,
9599f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceXlibPresentationSupportKHR", "queueFamilyIndex");
9600f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9601f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
9602f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9603f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
9604f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9605f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
9606f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result =
9607f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        instance_data->dispatch_table.GetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, dpy, visualID);
9608f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9609f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
9610f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
9611cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
9612747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
961340921785005eb449ec7c18229f0d84c879708b8aChris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
961440921785005eb449ec7c18229f0d84c879708b8aChris Forbes                                                                       VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
961556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
961640921785005eb449ec7c18229f0d84c879708b8aChris Forbes
961740921785005eb449ec7c18229f0d84c879708b8aChris Forbes    std::unique_lock<std::mutex> lock(global_lock);
96189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
961940921785005eb449ec7c18229f0d84c879708b8aChris Forbes    lock.unlock();
962040921785005eb449ec7c18229f0d84c879708b8aChris Forbes
9621bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
9622bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
962340921785005eb449ec7c18229f0d84c879708b8aChris Forbes
962440921785005eb449ec7c18229f0d84c879708b8aChris Forbes    if (result == VK_SUCCESS) {
962540921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
962640921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->surfaceCapabilities = *pSurfaceCapabilities;
962740921785005eb449ec7c18229f0d84c879708b8aChris Forbes    }
962840921785005eb449ec7c18229f0d84c879708b8aChris Forbes
962940921785005eb449ec7c18229f0d84c879708b8aChris Forbes    return result;
963040921785005eb449ec7c18229f0d84c879708b8aChris Forbes}
963140921785005eb449ec7c18229f0d84c879708b8aChris Forbes
963235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardtstatic void PostCallRecordGetPhysicalDeviceSurfaceCapabilities2KHR(instance_layer_data *instanceData,
963335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkPhysicalDevice physicalDevice,
963435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkSurfaceCapabilities2KHR *pSurfaceCapabilities) {
963535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    std::unique_lock<std::mutex> lock(global_lock);
963635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
963735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
963835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities = pSurfaceCapabilities->surfaceCapabilities;
963935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
964035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
964135b630211642e709485879a2e8859736f0ab16a0Mike SchuchardtVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice,
964235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                        const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
964335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                        VkSurfaceCapabilities2KHR *pSurfaceCapabilities) {
964435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
964535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
964635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto result =
964735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        instanceData->dispatch_table.GetPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, pSurfaceInfo, pSurfaceCapabilities);
964835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
964935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (result == VK_SUCCESS) {
965035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        PostCallRecordGetPhysicalDeviceSurfaceCapabilities2KHR(instanceData, physicalDevice, pSurfaceCapabilities);
965135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
965235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
965335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    return result;
965435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
965535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
965635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardtstatic void PostCallRecordGetPhysicalDeviceSurfaceCapabilities2EXT(instance_layer_data *instanceData,
965735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkPhysicalDevice physicalDevice,
965835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
965935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    std::unique_lock<std::mutex> lock(global_lock);
966035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
966135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
966235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.minImageCount = pSurfaceCapabilities->minImageCount;
966335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.maxImageCount = pSurfaceCapabilities->maxImageCount;
966435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.currentExtent = pSurfaceCapabilities->currentExtent;
966535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.minImageExtent = pSurfaceCapabilities->minImageExtent;
966635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.maxImageExtent = pSurfaceCapabilities->maxImageExtent;
966735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.maxImageArrayLayers = pSurfaceCapabilities->maxImageArrayLayers;
966835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.supportedTransforms = pSurfaceCapabilities->supportedTransforms;
966935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.currentTransform = pSurfaceCapabilities->currentTransform;
967035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.supportedCompositeAlpha = pSurfaceCapabilities->supportedCompositeAlpha;
967135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.supportedUsageFlags = pSurfaceCapabilities->supportedUsageFlags;
967235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
967335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
967435b630211642e709485879a2e8859736f0ab16a0Mike SchuchardtVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
967535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                        VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
967635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
967735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
967835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto result =
967935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        instanceData->dispatch_table.GetPhysicalDeviceSurfaceCapabilities2EXT(physicalDevice, surface, pSurfaceCapabilities);
968035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
968135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (result == VK_SUCCESS) {
968235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        PostCallRecordGetPhysicalDeviceSurfaceCapabilities2EXT(instanceData, physicalDevice, pSurfaceCapabilities);
968335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
968435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
968535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    return result;
968635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
968735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
9688418a8711f3301f3027a900bb45daaf0892f4e644Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
9689418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes                                                                  VkSurfaceKHR surface, VkBool32 *pSupported) {
9690f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
969156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
9692f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9693418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
9694f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
96959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
9696f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9697315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2ee009ea,
9698f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceSurfaceSupportKHR", "queueFamilyIndex");
9699f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9700418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    lock.unlock();
9701418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
9702f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
9703f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
9704bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
9705bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
9706418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
9707418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    if (result == VK_SUCCESS) {
97080bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        surface_state->gpu_queue_support[{physicalDevice, queueFamilyIndex}] = (*pSupported == VK_TRUE);
9709418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    }
9710418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
9711418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    return result;
9712418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes}
9713418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
97149e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
97159e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       uint32_t *pPresentModeCount,
97169e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       VkPresentModeKHR *pPresentModes) {
97173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
971856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
97199e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
97209e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    // TODO: this isn't quite right. available modes may differ by surface AND physical device.
97219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
9722bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState;
97239e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
97249e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (pPresentModes) {
97259e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        // Compare the preliminary value of *pPresentModeCount with the value this time:
9726bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_mode_count = (uint32_t)physical_device_state->present_modes.size();
97279e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        switch (call_state) {
9728cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
97293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
9730bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
97319b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
9732cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with non-NULL pPresentModeCount; but no prior positive "
9733cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pPresentModeCount.");
9734cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9735cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
9736cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // both query count and query details
9737cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (*pPresentModeCount != prev_mode_count) {
97383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
97399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice), __LINE__,
97409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    DEVLIMITS_COUNT_MISMATCH, "DL",
97413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with *pPresentModeCount (%u) that "
97423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "differs from the value "
97433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "(%u) that was returned when pPresentModes was NULL.",
97443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    *pPresentModeCount, prev_mode_count);
9745cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
9746cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
97479e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
97489e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
97499e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    lock.unlock();
97509e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
97513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
97529e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
9753bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount,
9754bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                        pPresentModes);
97559e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
97569e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
97579e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        lock.lock();
97589e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
97599e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (*pPresentModeCount) {
9760cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
97619e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (*pPresentModeCount > physical_device_state->present_modes.size())
97629e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes.resize(*pPresentModeCount);
97639e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
97649e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pPresentModes) {
9765cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
97669e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            for (uint32_t i = 0; i < *pPresentModeCount; i++) {
97679e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes[i] = pPresentModes[i];
97689e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            }
97699e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
97705faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
97715faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
97725faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    return result;
97735faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes}
97745faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
97755faa662f6859b01c72d79027abde363d5f10dcd7Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
97765faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  uint32_t *pSurfaceFormatCount,
97775faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  VkSurfaceFormatKHR *pSurfaceFormats) {
97783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
977956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
97805faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
97819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
9782bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState;
97835faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
97845faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (pSurfaceFormats) {
9785bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_format_count = (uint32_t)physical_device_state->surface_formats.size();
97865faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
97875faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        switch (call_state) {
9788cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
9789cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Since we haven't recorded a preliminary value of *pSurfaceFormatCount, that likely means that the application
9790cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // didn't
9791cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // previously call this function with a NULL value of pSurfaceFormats:
97923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
9793bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
97949b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
9795cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount; but no prior positive "
9796cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pSurfaceFormats.");
9797cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
9799cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (prev_format_count != *pSurfaceFormatCount) {
98003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
9801cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
98029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice), __LINE__,
9803cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        DEVLIMITS_COUNT_MISMATCH, "DL",
9804cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount, and with pSurfaceFormats "
9805cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "set "
9806cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "to "
9807cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "a value (%u) that is greater than the value (%u) that was returned when pSurfaceFormatCount was NULL.",
9808cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        *pSurfaceFormatCount, prev_format_count);
9809cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
9810cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
98119e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
98129e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
98135faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    lock.unlock();
98145faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
98153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
98169e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
98175faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    // Call down the call chain:
98185faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount,
98195faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                                   pSurfaceFormats);
98205faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
98215faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
98225faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        lock.lock();
98235faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
98245faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (*pSurfaceFormatCount) {
9825cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
98265faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (*pSurfaceFormatCount > physical_device_state->surface_formats.size())
98275faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats.resize(*pSurfaceFormatCount);
98285faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
98295faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (pSurfaceFormats) {
9830cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
98315faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
98325faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats[i] = pSurfaceFormats[i];
98335faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
98345faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
98355faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
98369e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    return result;
98379e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes}
98389e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
983935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardtstatic void PostCallRecordGetPhysicalDeviceSurfaceFormats2KHR(instance_layer_data *instanceData, VkPhysicalDevice physicalDevice,
984035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                              uint32_t *pSurfaceFormatCount, VkSurfaceFormat2KHR *pSurfaceFormats) {
984135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    std::unique_lock<std::mutex> lock(global_lock);
984235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
984335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (*pSurfaceFormatCount) {
984435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        if (physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState < QUERY_COUNT) {
984535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState = QUERY_COUNT;
984635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        }
984735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        if (*pSurfaceFormatCount > physicalDeviceState->surface_formats.size())
984835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->surface_formats.resize(*pSurfaceFormatCount);
984935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
985035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (pSurfaceFormats) {
985135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        if (physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState < QUERY_DETAILS) {
985235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState = QUERY_DETAILS;
985335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        }
985435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
985535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->surface_formats[i] = pSurfaceFormats[i].surfaceFormat;
985635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        }
985735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
985835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
985935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
986035b630211642e709485879a2e8859736f0ab16a0Mike SchuchardtVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice,
986135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
986235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   uint32_t *pSurfaceFormatCount,
986335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkSurfaceFormat2KHR *pSurfaceFormats) {
986435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
986535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto result = instanceData->dispatch_table.GetPhysicalDeviceSurfaceFormats2KHR(physicalDevice, pSurfaceInfo,
986635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                                   pSurfaceFormatCount, pSurfaceFormats);
986735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
986835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        PostCallRecordGetPhysicalDeviceSurfaceFormats2KHR(instanceData, physicalDevice, pSurfaceFormatCount, pSurfaceFormats);
986935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
987035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    return result;
987135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
987235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
9873bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
9874bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
9875bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkAllocationCallbacks *pAllocator,
9876bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            VkDebugReportCallbackEXT *pMsgCallback) {
987756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
98789172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkResult res = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
98795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == res) {
9880b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
98818860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        res = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
98825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
98835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
98845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9886bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
988789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                         const VkAllocationCallbacks *pAllocator) {
988856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
98899172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
9890b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
98918860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_destroy_msg_callback(instance_data->report_data, msgCallback, pAllocator);
98925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9894bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
9895bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
9896bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
989756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
98989172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
98995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9901bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
9902a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
9903a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
9904a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
9905bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
9906bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkLayerProperties *pProperties) {
9907a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
9908a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
9909a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
9910bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
9911bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                    VkExtensionProperties *pProperties) {
9912a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
9913a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
9914a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
9915a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return VK_ERROR_LAYER_NOT_PRESENT;
9916a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
9917a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
9918bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
9919bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
9920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
9921a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
9922a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    assert(physicalDevice);
9923a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
992456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
99259172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
992608939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
992708939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
9928582b6ed09649188d55ed3b6237352caf9f3384a9Mike WeiblenVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDeviceGroupsKHX(
9929582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupPropertiesKHX *pPhysicalDeviceGroupProperties) {
99303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9931582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
9932582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen
9933582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    if (instance_data) {
9934582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        // For this instance, flag when EnumeratePhysicalDeviceGroupsKHX goes to QUERY_COUNT and then QUERY_DETAILS.
9935582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        if (NULL == pPhysicalDeviceGroupProperties) {
9936582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_COUNT;
9937582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        } else {
9938582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            if (UNCALLED == instance_data->vkEnumeratePhysicalDeviceGroupsState) {
9939582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // Flag warning here. You can call this without having queried the count, but it may not be
9940582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // robust on platforms with multiple physical devices.
99413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
99423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
99433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "Call sequence has vkEnumeratePhysicalDeviceGroupsKHX() w/ non-NULL "
99443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "pPhysicalDeviceGroupProperties. You should first "
99453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "call vkEnumeratePhysicalDeviceGroupsKHX() w/ NULL pPhysicalDeviceGroupProperties to query "
99463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "pPhysicalDeviceGroupCount.");
9947582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            } // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
9948582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            else if (instance_data->physical_device_groups_count != *pPhysicalDeviceGroupCount) {
9949582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // Having actual count match count from app is not a requirement, so this can be a warning
99503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
9951582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
99523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
99533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call to vkEnumeratePhysicalDeviceGroupsKHX() w/ pPhysicalDeviceGroupCount value %u, but actual count "
99543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "supported by this instance is %u.",
99553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            *pPhysicalDeviceGroupCount, instance_data->physical_device_groups_count);
9956582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            }
9957582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_DETAILS;
9958582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
99593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        if (skip) {
9960582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            return VK_ERROR_VALIDATION_FAILED_EXT;
9961582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
9962582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        VkResult result = instance_data->dispatch_table.EnumeratePhysicalDeviceGroupsKHX(instance, pPhysicalDeviceGroupCount,
9963582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            pPhysicalDeviceGroupProperties);
9964582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        if (NULL == pPhysicalDeviceGroupProperties) {
9965582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->physical_device_groups_count = *pPhysicalDeviceGroupCount;
9966582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        } else if (result == VK_SUCCESS) { // Save physical devices
9967582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
9968582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                for (uint32_t j = 0; j < pPhysicalDeviceGroupProperties[i].physicalDeviceCount; j++) {
9969582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    VkPhysicalDevice cur_phys_dev = pPhysicalDeviceGroupProperties[i].physicalDevices[j];
9970582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    auto &phys_device_state = instance_data->physical_device_map[cur_phys_dev];
9971582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    phys_device_state.phys_device = cur_phys_dev;
9972582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    // Init actual features for each physical device
9973582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    instance_data->dispatch_table.GetPhysicalDeviceFeatures(cur_phys_dev, &phys_device_state.features);
9974582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                }
9975582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            }
9976582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
9977582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        return result;
9978582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    } else {
9979582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__,
99809b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                DEVLIMITS_INVALID_INSTANCE, "DL",
99819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                "Invalid instance (0x%" PRIxLEAST64 ") passed into vkEnumeratePhysicalDeviceGroupsKHX().",
99829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(instance));
9983582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    }
9984582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    return VK_ERROR_VALIDATION_FAILED_EXT;
9985582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen}
9986582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen
99876246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorUpdateTemplateKHR(VkDevice device,
99886246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
99896246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 const VkAllocationCallbacks *pAllocator,
99906246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
99916246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
9992a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski    VkResult result =
9993a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski        dev_data->dispatch_table.CreateDescriptorUpdateTemplateKHR(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
99946246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    if (VK_SUCCESS == result) {
99956246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
99966246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        // Shadow template createInfo for later updates
9997a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski        safe_VkDescriptorUpdateTemplateCreateInfoKHR *local_create_info =
9998a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski            new safe_VkDescriptorUpdateTemplateCreateInfoKHR(pCreateInfo);
99996246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info));
100006246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        dev_data->desc_template_map[*pDescriptorUpdateTemplate] = std::move(template_state);
100016246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    }
100026246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    return result;
100036246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
100046246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
100056246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplateKHR(VkDevice device,
100066246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
100076246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              const VkAllocationCallbacks *pAllocator) {
100086246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
100096246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
100106246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->desc_template_map.erase(descriptorUpdateTemplate);
100116246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    lock.unlock();
100126246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);
100136246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
100146246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
1001525f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSetsWithTemplate()
1001625f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinskistatic void PostCallRecordUpdateDescriptorSetWithTemplateKHR(layer_data *device_data, VkDescriptorSet descriptorSet,
1001725f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski                                                             VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
1001825f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski                                                             const void *pData) {
1001967fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    auto const template_map_entry = device_data->desc_template_map.find(descriptorUpdateTemplate);
1002067fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    if (template_map_entry == device_data->desc_template_map.end()) {
1002167fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski        assert(0);
1002267fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    }
1002367fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
1002425f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski    cvdescriptorset::PerformUpdateDescriptorSetsWithTemplateKHR(device_data, descriptorSet, template_map_entry->second, pData);
1002567fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski}
1002667fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
100276246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
100286246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
100296246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              const void *pData) {
1003067fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1003167fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    device_data->dispatch_table.UpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, pData);
1003267fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
1003367fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    PostCallRecordUpdateDescriptorSetWithTemplateKHR(device_data, descriptorSet, descriptorUpdateTemplate, pData);
100346246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
100356246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
100366246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
100376246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                               VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
100386246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                               VkPipelineLayout layout, uint32_t set, const void *pData) {
100396246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
100406246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set, pData);
100416246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
100426246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
10043991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinskistatic void PostCallRecordGetPhysicalDeviceDisplayPlanePropertiesKHR(instance_layer_data *instanceData,
10044991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                                     VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
10045991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                                     VkDisplayPlanePropertiesKHR *pProperties) {
10046991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
10047991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    auto physical_device_state = GetPhysicalDeviceState(instanceData, physicalDevice);
10048991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10049991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if (*pPropertyCount) {
10050991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState < QUERY_COUNT) {
10051991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState = QUERY_COUNT;
10052991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        }
10053991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        physical_device_state->display_plane_property_count = *pPropertyCount;
10054991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    }
10055991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if (pProperties) {
10056991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState < QUERY_DETAILS) {
10057991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState = QUERY_DETAILS;
10058991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        }
10059991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    }
10060991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski}
10061991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10062991f2555bc4f571e30b584937c7959805dff67c6Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
10063991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                                          VkDisplayPlanePropertiesKHR *pProperties) {
10064991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    VkResult result = VK_SUCCESS;
10065991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
10066991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10067991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    result = instance_data->dispatch_table.GetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, pPropertyCount, pProperties);
10068991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10069991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
10070991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        PostCallRecordGetPhysicalDeviceDisplayPlanePropertiesKHR(instance_data, physicalDevice, pPropertyCount, pProperties);
10071991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    }
10072991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10073991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    return result;
10074991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski}
10075991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10076991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinskistatic bool ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_layer_data *instance_data,
10077991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                                    VkPhysicalDevice physicalDevice, uint32_t planeIndex,
10078991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                                    const char *api_name) {
10079991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    bool skip = false;
10080991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
10081991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState == UNCALLED) {
10082991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        skip |= log_msg(
10083991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
10084991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            HandleToUint64(physicalDevice), __LINE__, SWAPCHAIN_GET_SUPPORTED_DISPLAYS_WITHOUT_QUERY, "DL",
10085991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            "Potential problem with calling %s() without first querying vkGetPhysicalDeviceDisplayPlanePropertiesKHR.", api_name);
10086991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    } else {
10087991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        if (planeIndex >= physical_device_state->display_plane_property_count) {
10088991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            skip |= log_msg(
10089991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
10090991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                HandleToUint64(physicalDevice), __LINE__, VALIDATION_ERROR_29c009c2, "DL",
10091991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                "%s(): planeIndex must be in the range [0, %d] that was returned by vkGetPhysicalDeviceDisplayPlanePropertiesKHR. "
10092991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                "Do you have the plane index hardcoded? %s",
10093991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                api_name, physical_device_state->display_plane_property_count - 1, validation_error_map[VALIDATION_ERROR_29c009c2]);
10094991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        }
10095991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    }
10096991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    return skip;
10097991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski}
10098991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10099991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinskistatic bool PreCallValidateGetDisplayPlaneSupportedDisplaysKHR(instance_layer_data *instance_data, VkPhysicalDevice physicalDevice,
10100991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                               uint32_t planeIndex) {
10101991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    bool skip = false;
10102991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
10103991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    skip |= ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_data, physicalDevice, planeIndex,
10104991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                                    "vkGetDisplayPlaneSupportedDisplaysKHR");
10105991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    return skip;
10106991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski}
10107991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10108991f2555bc4f571e30b584937c7959805dff67c6Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
10109991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                                   uint32_t *pDisplayCount, VkDisplayKHR *pDisplays) {
10110991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
10111991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
10112991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    bool skip = PreCallValidateGetDisplayPlaneSupportedDisplaysKHR(instance_data, physicalDevice, planeIndex);
10113991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if (!skip) {
10114991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        result =
10115991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski            instance_data->dispatch_table.GetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, pDisplayCount, pDisplays);
10116991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    }
10117991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    return result;
10118991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski}
10119991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10120991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinskistatic bool PreCallValidateGetDisplayPlaneCapabilitiesKHR(instance_layer_data *instance_data, VkPhysicalDevice physicalDevice,
10121991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                          uint32_t planeIndex) {
10122991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    bool skip = false;
10123991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
10124991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    skip |= ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_data, physicalDevice, planeIndex,
10125991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                                    "vkGetDisplayPlaneCapabilitiesKHR");
10126991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    return skip;
10127991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski}
10128991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10129991f2555bc4f571e30b584937c7959805dff67c6Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode,
10130991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski                                                              uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR *pCapabilities) {
10131991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
10132991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
10133991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    bool skip = PreCallValidateGetDisplayPlaneCapabilitiesKHR(instance_data, physicalDevice, planeIndex);
10134991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10135991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    if (!skip) {
10136991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski        result = instance_data->dispatch_table.GetDisplayPlaneCapabilitiesKHR(physicalDevice, mode, planeIndex, pCapabilities);
10137991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    }
10138991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
10139991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    return result;
10140991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski}
10141991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski
101423616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName);
101433616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName);
101443616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName);
101453616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski
101463616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski// Map of all APIs to be intercepted by this layer
101473616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinskistatic const std::unordered_map<std::string, void*> name_to_funcptr_map = {
101483616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetInstanceProcAddr", (void*)GetInstanceProcAddr},
101493616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vk_layerGetPhysicalDeviceProcAddr", (void*)GetPhysicalDeviceProcAddr},
101503616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetDeviceProcAddr", (void*)GetDeviceProcAddr},
101513616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateInstance", (void*)CreateInstance},
101523616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDevice", (void*)CreateDevice},
101533616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumeratePhysicalDevices", (void*)EnumeratePhysicalDevices},
101543616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceQueueFamilyProperties", (void*)GetPhysicalDeviceQueueFamilyProperties},
101553616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyInstance", (void*)DestroyInstance},
101563616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateInstanceLayerProperties", (void*)EnumerateInstanceLayerProperties},
101573616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateDeviceLayerProperties", (void*)EnumerateDeviceLayerProperties},
101583616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateInstanceExtensionProperties", (void*)EnumerateInstanceExtensionProperties},
101593616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateDeviceExtensionProperties", (void*)EnumerateDeviceExtensionProperties},
101603616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDescriptorUpdateTemplateKHR", (void*)CreateDescriptorUpdateTemplateKHR},
101613616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDescriptorUpdateTemplateKHR", (void*)DestroyDescriptorUpdateTemplateKHR},
101623616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkUpdateDescriptorSetWithTemplateKHR", (void*)UpdateDescriptorSetWithTemplateKHR},
101633616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdPushDescriptorSetWithTemplateKHR", (void*)CmdPushDescriptorSetWithTemplateKHR},
101643616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateSwapchainKHR", (void*)CreateSwapchainKHR},
101653616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySwapchainKHR", (void*)DestroySwapchainKHR},
101663616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetSwapchainImagesKHR", (void*)GetSwapchainImagesKHR},
101673616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAcquireNextImageKHR", (void*)AcquireNextImageKHR},
101683616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueuePresentKHR", (void*)QueuePresentKHR},
101693616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueueSubmit", (void*)QueueSubmit},
101703616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkWaitForFences", (void*)WaitForFences},
101713616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetFenceStatus", (void*)GetFenceStatus},
101723616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueueWaitIdle", (void*)QueueWaitIdle},
101733616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDeviceWaitIdle", (void*)DeviceWaitIdle},
101743616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetDeviceQueue", (void*)GetDeviceQueue},
101753616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDevice", (void*)DestroyDevice},
101763616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyFence", (void*)DestroyFence},
101773616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetFences", (void*)ResetFences},
101783616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySemaphore", (void*)DestroySemaphore},
101793616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyEvent", (void*)DestroyEvent},
101803616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyQueryPool", (void*)DestroyQueryPool},
101813616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyBuffer", (void*)DestroyBuffer},
101823616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyBufferView", (void*)DestroyBufferView},
101833616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyImage", (void*)DestroyImage},
101843616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyImageView", (void*)DestroyImageView},
101853616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyShaderModule", (void*)DestroyShaderModule},
101863616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyPipeline", (void*)DestroyPipeline},
101873616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyPipelineLayout", (void*)DestroyPipelineLayout},
101883616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySampler", (void*)DestroySampler},
101893616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDescriptorSetLayout", (void*)DestroyDescriptorSetLayout},
101903616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDescriptorPool", (void*)DestroyDescriptorPool},
101913616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyFramebuffer", (void*)DestroyFramebuffer},
101923616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyRenderPass", (void*)DestroyRenderPass},
101933616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateBuffer", (void*)CreateBuffer},
101943616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateBufferView", (void*)CreateBufferView},
101953616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateImage", (void*)CreateImage},
101963616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateImageView", (void*)CreateImageView},
101973616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateFence", (void*)CreateFence},
101983616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreatePipelineCache", (void*)CreatePipelineCache},
101993616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyPipelineCache", (void*)DestroyPipelineCache},
102003616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPipelineCacheData", (void*)GetPipelineCacheData},
102013616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkMergePipelineCaches", (void*)MergePipelineCaches},
102023616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateGraphicsPipelines", (void*)CreateGraphicsPipelines},
102033616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateComputePipelines", (void*)CreateComputePipelines},
102043616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateSampler", (void*)CreateSampler},
102053616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDescriptorSetLayout", (void*)CreateDescriptorSetLayout},
102063616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreatePipelineLayout", (void*)CreatePipelineLayout},
102073616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDescriptorPool", (void*)CreateDescriptorPool},
102083616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetDescriptorPool", (void*)ResetDescriptorPool},
102093616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAllocateDescriptorSets", (void*)AllocateDescriptorSets},
102103616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFreeDescriptorSets", (void*)FreeDescriptorSets},
102113616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkUpdateDescriptorSets", (void*)UpdateDescriptorSets},
102123616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateCommandPool", (void*)CreateCommandPool},
102133616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyCommandPool", (void*)DestroyCommandPool},
102143616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetCommandPool", (void*)ResetCommandPool},
102153616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateQueryPool", (void*)CreateQueryPool},
102163616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAllocateCommandBuffers", (void*)AllocateCommandBuffers},
102173616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFreeCommandBuffers", (void*)FreeCommandBuffers},
102183616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkBeginCommandBuffer", (void*)BeginCommandBuffer},
102193616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEndCommandBuffer", (void*)EndCommandBuffer},
102203616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetCommandBuffer", (void*)ResetCommandBuffer},
102213616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindPipeline", (void*)CmdBindPipeline},
102223616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetViewport", (void*)CmdSetViewport},
102233616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetScissor", (void*)CmdSetScissor},
102243616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetLineWidth", (void*)CmdSetLineWidth},
102253616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetDepthBias", (void*)CmdSetDepthBias},
102263616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetBlendConstants", (void*)CmdSetBlendConstants},
102273616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetDepthBounds", (void*)CmdSetDepthBounds},
102283616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetStencilCompareMask", (void*)CmdSetStencilCompareMask},
102293616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetStencilWriteMask", (void*)CmdSetStencilWriteMask},
102303616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetStencilReference", (void*)CmdSetStencilReference},
102313616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindDescriptorSets", (void*)CmdBindDescriptorSets},
102323616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindVertexBuffers", (void*)CmdBindVertexBuffers},
102333616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindIndexBuffer", (void*)CmdBindIndexBuffer},
102343616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDraw", (void*)CmdDraw},
102353616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDrawIndexed", (void*)CmdDrawIndexed},
102363616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDrawIndirect", (void*)CmdDrawIndirect},
102373616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDrawIndexedIndirect", (void*)CmdDrawIndexedIndirect},
102383616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDispatch", (void*)CmdDispatch},
102393616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDispatchIndirect", (void*)CmdDispatchIndirect},
102403616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyBuffer", (void*)CmdCopyBuffer},
102413616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyImage", (void*)CmdCopyImage},
102423616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBlitImage", (void*)CmdBlitImage},
102433616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyBufferToImage", (void*)CmdCopyBufferToImage},
102443616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyImageToBuffer", (void*)CmdCopyImageToBuffer},
102453616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdUpdateBuffer", (void*)CmdUpdateBuffer},
102463616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdFillBuffer", (void*)CmdFillBuffer},
102473616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdClearColorImage", (void*)CmdClearColorImage},
102483616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdClearDepthStencilImage", (void*)CmdClearDepthStencilImage},
102493616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdClearAttachments", (void*)CmdClearAttachments},
102503616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdResolveImage", (void*)CmdResolveImage},
102513616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetImageSubresourceLayout", (void*)GetImageSubresourceLayout},
102523616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetEvent", (void*)CmdSetEvent},
102533616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdResetEvent", (void*)CmdResetEvent},
102543616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdWaitEvents", (void*)CmdWaitEvents},
102553616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdPipelineBarrier", (void*)CmdPipelineBarrier},
102563616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBeginQuery", (void*)CmdBeginQuery},
102573616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdEndQuery", (void*)CmdEndQuery},
102583616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdResetQueryPool", (void*)CmdResetQueryPool},
102593616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyQueryPoolResults", (void*)CmdCopyQueryPoolResults},
102603616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdPushConstants", (void*)CmdPushConstants},
102613616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdWriteTimestamp", (void*)CmdWriteTimestamp},
102623616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateFramebuffer", (void*)CreateFramebuffer},
102633616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateShaderModule", (void*)CreateShaderModule},
102643616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateRenderPass", (void*)CreateRenderPass},
102653616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBeginRenderPass", (void*)CmdBeginRenderPass},
102663616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdNextSubpass", (void*)CmdNextSubpass},
102673616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdEndRenderPass", (void*)CmdEndRenderPass},
102683616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdExecuteCommands", (void*)CmdExecuteCommands},
102693616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkSetEvent", (void*)SetEvent},
102703616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkMapMemory", (void*)MapMemory},
102713616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkUnmapMemory", (void*)UnmapMemory},
102723616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFlushMappedMemoryRanges", (void*)FlushMappedMemoryRanges},
102733616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkInvalidateMappedMemoryRanges", (void*)InvalidateMappedMemoryRanges},
102743616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAllocateMemory", (void*)AllocateMemory},
102753616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFreeMemory", (void*)FreeMemory},
102763616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkBindBufferMemory", (void*)BindBufferMemory},
102773616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetBufferMemoryRequirements", (void*)GetBufferMemoryRequirements},
102783616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetImageMemoryRequirements", (void*)GetImageMemoryRequirements},
102793616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetQueryPoolResults", (void*)GetQueryPoolResults},
102803616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkBindImageMemory", (void*)BindImageMemory},
102813616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueueBindSparse", (void*)QueueBindSparse},
102823616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateSemaphore", (void*)CreateSemaphore},
102833616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateEvent", (void*)CreateEvent},
102843616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_ANDROID_KHR
102853616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateAndroidSurfaceKHR", (void*)CreateAndroidSurfaceKHR},
102863616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
102873616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_MIR_KHR
102883616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateMirSurfaceKHR", (void*)CreateMirSurfaceKHR},
102893616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceMirPresentationSupportKHR", (void*)GetPhysicalDeviceMirPresentationSupportKHR},
102903616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
102913616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_WAYLAND_KHR
102923616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateWaylandSurfaceKHR", (void*)CreateWaylandSurfaceKHR},
102933616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceWaylandPresentationSupportKHR", (void*)GetPhysicalDeviceWaylandPresentationSupportKHR},
102943616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
102953616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_WIN32_KHR
102963616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateWin32SurfaceKHR", (void*)CreateWin32SurfaceKHR},
102973616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceWin32PresentationSupportKHR", (void*)GetPhysicalDeviceWin32PresentationSupportKHR},
102983616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
102993616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_XCB_KHR
103003616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateXcbSurfaceKHR", (void*)CreateXcbSurfaceKHR},
103013616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceXcbPresentationSupportKHR", (void*)GetPhysicalDeviceXcbPresentationSupportKHR},
103023616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
103033616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_XLIB_KHR
103043616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateXlibSurfaceKHR", (void*)CreateXlibSurfaceKHR},
103053616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceXlibPresentationSupportKHR", (void*)GetPhysicalDeviceXlibPresentationSupportKHR},
103063616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
103073616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDisplayPlaneSurfaceKHR", (void*)CreateDisplayPlaneSurfaceKHR},
103083616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySurfaceKHR", (void*)DestroySurfaceKHR},
103093616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", (void*)GetPhysicalDeviceSurfaceCapabilitiesKHR},
103103616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceCapabilities2KHR", (void*)GetPhysicalDeviceSurfaceCapabilities2KHR},
103113616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceCapabilities2EXT", (void*)GetPhysicalDeviceSurfaceCapabilities2EXT},
103123616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceSupportKHR", (void*)GetPhysicalDeviceSurfaceSupportKHR},
103133616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfacePresentModesKHR", (void*)GetPhysicalDeviceSurfacePresentModesKHR},
103143616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceFormatsKHR", (void*)GetPhysicalDeviceSurfaceFormatsKHR},
103153616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceFormats2KHR", (void*)GetPhysicalDeviceSurfaceFormats2KHR},
103163616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceQueueFamilyProperties2KHR", (void*)GetPhysicalDeviceQueueFamilyProperties2KHR},
103173616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumeratePhysicalDeviceGroupsKHX", (void*)EnumeratePhysicalDeviceGroupsKHX},
103183616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDebugReportCallbackEXT", (void*)CreateDebugReportCallbackEXT},
103193616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDebugReportCallbackEXT", (void*)DestroyDebugReportCallbackEXT},
103203616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDebugReportMessageEXT", (void*)DebugReportMessageEXT},
10321991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    {"vkGetPhysicalDeviceDisplayPlanePropertiesKHR", (void*)GetPhysicalDeviceDisplayPlanePropertiesKHR},
10322991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    {"GetDisplayPlaneSupportedDisplaysKHR", (void*)GetDisplayPlaneSupportedDisplaysKHR},
10323991f2555bc4f571e30b584937c7959805dff67c6Mark Lobodzinski    {"GetDisplayPlaneCapabilitiesKHR", (void*)GetDisplayPlaneCapabilitiesKHR},
103243616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski};
10325b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
103263616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
103273616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    assert(device);
103283616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
103295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
103303616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    // Is API to be intercepted by this layer?
103313616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    const auto &item = name_to_funcptr_map.find(funcName);
103323616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    if (item != name_to_funcptr_map.end()) {
103333616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
103343616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    }
1033509a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
103363616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    auto &table = device_data->dispatch_table;
10337cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetDeviceProcAddr) return nullptr;
103383616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    return table.GetDeviceProcAddr(device, funcName);
103395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
103405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1034189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
103423616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    instance_layer_data *instance_data;
103433616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    // Is API to be intercepted by this layer?
103443616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    const auto &item = name_to_funcptr_map.find(funcName);
103453616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    if (item != name_to_funcptr_map.end()) {
103463616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
103473616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    }
10348b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
103493616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
103504a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = instance_data->dispatch_table;
10351cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetInstanceProcAddr) return nullptr;
103524a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetInstanceProcAddr(instance, funcName);
103535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1035408939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
10355b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
10356b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(instance);
1035756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
10358b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
10359b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    auto &table = instance_data->dispatch_table;
10360cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetPhysicalDeviceProcAddr) return nullptr;
10361b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return table.GetPhysicalDeviceProcAddr(instance, funcName);
10362b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
10363b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
10364cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski}  // namespace core_validation
10365d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
10366a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu// loader-layer interface v0, just wrappers since there is only a layer
10367d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
10368bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
10369bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                      VkExtensionProperties *pProperties) {
10370a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
1037108939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1037208939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
10373bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
10374bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                  VkLayerProperties *pProperties) {
10375a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceLayerProperties(pCount, pProperties);
1037608939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1037708939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
10378bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
10379bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                VkLayerProperties *pProperties) {
10380a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
10381a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
10382a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
10383d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
10384d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
10385d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
10386d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    const char *pLayerName, uint32_t *pCount,
10387d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    VkExtensionProperties *pProperties) {
10388a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
10389a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
10390a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    return core_validation::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
10391d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
10392d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
10393d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
1039489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetDeviceProcAddr(dev, funcName);
10395d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
10396d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
10397d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
1039889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetInstanceProcAddr(instance, funcName);
1039908939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
10400b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
10401bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
10402bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                           const char *funcName) {
10403b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return core_validation::GetPhysicalDeviceProcAddr(instance, funcName);
10404b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
10405b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
10406b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
10407b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct != NULL);
10408b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
10409b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
10410b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    // Fill in the function pointers if our version is at least capable of having the structure contain them.
10411b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
10412b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
10413b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
10414b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
10415b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
10416b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
10417b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
10418b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        core_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
10419b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
10420b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
10421b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
10422b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
10423b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return VK_SUCCESS;
10424b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
10425