core_validation.cpp revision 26c548826ff0f83d12c769b51e7d6f76d1265c0e
1/* Copyright (c) 2015-2016 The Khronos Group Inc. 2 * Copyright (c) 2015-2016 Valve Corporation 3 * Copyright (c) 2015-2016 LunarG, Inc. 4 * Copyright (C) 2015-2016 Google Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and/or associated documentation files (the "Materials"), to 8 * deal in the Materials without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Materials, and to permit persons to whom the Materials 11 * are furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice(s) and this permission notice shall be included 14 * in all copies or substantial portions of the Materials. 15 * 16 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 * 20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE 23 * USE OR OTHER DEALINGS IN THE MATERIALS 24 * 25 * Author: Cody Northrop <cnorthrop@google.com> 26 * Author: Michael Lentine <mlentine@google.com> 27 * Author: Tobin Ehlis <tobine@google.com> 28 * Author: Chia-I Wu <olv@google.com> 29 * Author: Chris Forbes <chrisf@ijw.co.nz> 30 * Author: Mark Lobodzinski <mark@lunarg.com> 31 * Author: Ian Elliott <ianelliott@google.com> 32 */ 33 34// Allow use of STL min and max functions in Windows 35#define NOMINMAX 36 37// Turn on mem_tracker merged code 38#define MTMERGESOURCE 1 39 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <assert.h> 44#include <unordered_map> 45#include <unordered_set> 46#include <map> 47#include <string> 48#include <iostream> 49#include <algorithm> 50#include <list> 51#include <SPIRV/spirv.hpp> 52#include <set> 53 54#include "vk_loader_platform.h" 55#include "vk_dispatch_table_helper.h" 56#include "vk_struct_string_helper_cpp.h" 57#if defined(__GNUC__) 58#pragma GCC diagnostic ignored "-Wwrite-strings" 59#endif 60#if defined(__GNUC__) 61#pragma GCC diagnostic warning "-Wwrite-strings" 62#endif 63#include "vk_struct_size_helper.h" 64#include "core_validation.h" 65#include "vk_layer_config.h" 66#include "vk_layer_table.h" 67#include "vk_layer_data.h" 68#include "vk_layer_logging.h" 69#include "vk_layer_extension_utils.h" 70#include "vk_layer_utils.h" 71 72#if defined __ANDROID__ 73#include <android/log.h> 74#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "DS", __VA_ARGS__)) 75#else 76#define LOGCONSOLE(...) printf(__VA_ARGS__) 77#endif 78 79using std::unordered_map; 80using std::unordered_set; 81 82#if MTMERGESOURCE 83// WSI Image Objects bypass usual Image Object creation methods. A special Memory 84// Object value will be used to identify them internally. 85static const VkDeviceMemory MEMTRACKER_SWAP_CHAIN_IMAGE_KEY = (VkDeviceMemory)(-1); 86#endif 87// Track command pools and their command buffers 88struct CMD_POOL_INFO { 89 VkCommandPoolCreateFlags createFlags; 90 uint32_t queueFamilyIndex; 91 list<VkCommandBuffer> commandBuffers; // list container of cmd buffers allocated from this pool 92}; 93 94struct devExts { 95 VkBool32 wsi_enabled; 96 unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> swapchainMap; 97 unordered_map<VkImage, VkSwapchainKHR> imageToSwapchainMap; 98}; 99 100// fwd decls 101struct shader_module; 102struct render_pass; 103 104struct layer_data { 105 debug_report_data *report_data; 106 std::vector<VkDebugReportCallbackEXT> logging_callback; 107 VkLayerDispatchTable *device_dispatch_table; 108 VkLayerInstanceDispatchTable *instance_dispatch_table; 109#if MTMERGESOURCE 110// MTMERGESOURCE - stuff pulled directly from MT 111 uint64_t currentFenceId; 112 // Maps for tracking key structs related to mem_tracker state 113 unordered_map<VkDescriptorSet, MT_DESCRIPTOR_SET_INFO> descriptorSetMap; 114 // Images and Buffers are 2 objects that can have memory bound to them so they get special treatment 115 unordered_map<uint64_t, MT_OBJ_BINDING_INFO> imageBindingMap; 116 unordered_map<uint64_t, MT_OBJ_BINDING_INFO> bufferBindingMap; 117// MTMERGESOURCE - End of MT stuff 118#endif 119 devExts device_extensions; 120 vector<VkQueue> queues; // all queues under given device 121 // Global set of all cmdBuffers that are inFlight on this device 122 unordered_set<VkCommandBuffer> globalInFlightCmdBuffers; 123 // Layer specific data 124 unordered_map<VkSampler, unique_ptr<SAMPLER_NODE>> sampleMap; 125 unordered_map<VkImageView, VkImageViewCreateInfo> imageViewMap; 126 unordered_map<VkImage, IMAGE_NODE> imageMap; 127 unordered_map<VkBufferView, VkBufferViewCreateInfo> bufferViewMap; 128 unordered_map<VkBuffer, BUFFER_NODE> bufferMap; 129 unordered_map<VkPipeline, PIPELINE_NODE *> pipelineMap; 130 unordered_map<VkCommandPool, CMD_POOL_INFO> commandPoolMap; 131 unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_NODE *> descriptorPoolMap; 132 unordered_map<VkDescriptorSet, SET_NODE *> setMap; 133 unordered_map<VkDescriptorSetLayout, LAYOUT_NODE *> descriptorSetLayoutMap; 134 unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap; 135 unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> memObjMap; 136 unordered_map<VkFence, FENCE_NODE> fenceMap; 137 unordered_map<VkQueue, QUEUE_NODE> queueMap; 138 unordered_map<VkEvent, EVENT_NODE> eventMap; 139 unordered_map<QueryObject, bool> queryToStateMap; 140 unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap; 141 unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap; 142 unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap; 143 unordered_map<VkFramebuffer, FRAMEBUFFER_NODE> frameBufferMap; 144 unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap; 145 unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap; 146 unordered_map<VkRenderPass, RENDER_PASS_NODE *> renderPassMap; 147 unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap; 148 // Current render pass 149 VkRenderPassBeginInfo renderPassBeginInfo; 150 uint32_t currentSubpass; 151 152 // Device specific data 153 PHYS_DEV_PROPERTIES_NODE physDevProperties; 154// MTMERGESOURCE - added a couple of fields to constructor initializer 155 layer_data() 156 : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), 157#if MTMERGESOURCE 158 currentFenceId(1), 159#endif 160 device_extensions(){}; 161}; 162 163static const VkLayerProperties cv_global_layers[] = {{ 164 "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer", 165}}; 166 167template <class TCreateInfo> void ValidateLayerOrdering(const TCreateInfo &createInfo) { 168 bool foundLayer = false; 169 for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) { 170 if (!strcmp(createInfo.ppEnabledLayerNames[i], cv_global_layers[0].layerName)) { 171 foundLayer = true; 172 } 173 // This has to be logged to console as we don't have a callback at this point. 174 if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) { 175 LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.", 176 cv_global_layers[0].layerName); 177 } 178 } 179} 180 181// Code imported from shader_checker 182static void build_def_index(shader_module *); 183 184// A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words 185// without the caller needing to care too much about the physical SPIRV module layout. 186struct spirv_inst_iter { 187 std::vector<uint32_t>::const_iterator zero; 188 std::vector<uint32_t>::const_iterator it; 189 190 uint32_t len() { return *it >> 16; } 191 uint32_t opcode() { return *it & 0x0ffffu; } 192 uint32_t const &word(unsigned n) { return it[n]; } 193 uint32_t offset() { return (uint32_t)(it - zero); } 194 195 spirv_inst_iter() {} 196 197 spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {} 198 199 bool operator==(spirv_inst_iter const &other) { return it == other.it; } 200 201 bool operator!=(spirv_inst_iter const &other) { return it != other.it; } 202 203 spirv_inst_iter operator++(int) { /* x++ */ 204 spirv_inst_iter ii = *this; 205 it += len(); 206 return ii; 207 } 208 209 spirv_inst_iter operator++() { /* ++x; */ 210 it += len(); 211 return *this; 212 } 213 214 /* The iterator and the value are the same thing. */ 215 spirv_inst_iter &operator*() { return *this; } 216 spirv_inst_iter const &operator*() const { return *this; } 217}; 218 219struct shader_module { 220 /* the spirv image itself */ 221 vector<uint32_t> words; 222 /* a mapping of <id> to the first word of its def. this is useful because walking type 223 * trees, constant expressions, etc requires jumping all over the instruction stream. 224 */ 225 unordered_map<unsigned, unsigned> def_index; 226 227 shader_module(VkShaderModuleCreateInfo const *pCreateInfo) 228 : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)), 229 def_index() { 230 231 build_def_index(this); 232 } 233 234 /* expose begin() / end() to enable range-based for */ 235 spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); } /* first insn */ 236 spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); } /* just past last insn */ 237 /* given an offset into the module, produce an iterator there. */ 238 spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); } 239 240 /* gets an iterator to the definition of an id */ 241 spirv_inst_iter get_def(unsigned id) const { 242 auto it = def_index.find(id); 243 if (it == def_index.end()) { 244 return end(); 245 } 246 return at(it->second); 247 } 248}; 249 250// TODO : Do we need to guard access to layer_data_map w/ lock? 251static unordered_map<void *, layer_data *> layer_data_map; 252 253// TODO : This can be much smarter, using separate locks for separate global data 254static int globalLockInitialized = 0; 255static loader_platform_thread_mutex globalLock; 256#define MAX_TID 513 257static loader_platform_thread_id g_tidMapping[MAX_TID] = {0}; 258static uint32_t g_maxTID = 0; 259#if MTMERGESOURCE 260// MTMERGESOURCE - start of direct pull 261static VkPhysicalDeviceMemoryProperties memProps; 262 263static void clear_cmd_buf_and_mem_references(layer_data *my_data, const VkCommandBuffer cb); 264 265#define MAX_BINDING 0xFFFFFFFF 266 267static MT_OBJ_BINDING_INFO *get_object_binding_info(layer_data *my_data, uint64_t handle, VkDebugReportObjectTypeEXT type) { 268 MT_OBJ_BINDING_INFO *retValue = NULL; 269 switch (type) { 270 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: { 271 auto it = my_data->imageBindingMap.find(handle); 272 if (it != my_data->imageBindingMap.end()) 273 return &(*it).second; 274 break; 275 } 276 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: { 277 auto it = my_data->bufferBindingMap.find(handle); 278 if (it != my_data->bufferBindingMap.end()) 279 return &(*it).second; 280 break; 281 } 282 default: 283 break; 284 } 285 return retValue; 286} 287// MTMERGESOURCE - end section 288#endif 289template layer_data *get_my_data_ptr<layer_data>(void *data_key, std::unordered_map<void *, layer_data *> &data_map); 290 291// prototype 292static GLOBAL_CB_NODE *getCBNode(layer_data *, const VkCommandBuffer); 293 294#if MTMERGESOURCE 295static void delete_queue_info_list(layer_data *my_data) { 296 // Process queue list, cleaning up each entry before deleting 297 my_data->queueMap.clear(); 298} 299 300// Delete CBInfo from container and clear mem references to CB 301static void delete_cmd_buf_info(layer_data *my_data, VkCommandPool commandPool, const VkCommandBuffer cb) { 302 clear_cmd_buf_and_mem_references(my_data, cb); 303 // Delete the CBInfo info 304 my_data->commandPoolMap[commandPool].commandBuffers.remove(cb); 305 my_data->commandBufferMap.erase(cb); 306} 307 308static void add_object_binding_info(layer_data *my_data, const uint64_t handle, const VkDebugReportObjectTypeEXT type, 309 const VkDeviceMemory mem) { 310 switch (type) { 311 // Buffers and images are unique as their CreateInfo is in container struct 312 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: { 313 auto pCI = &my_data->bufferBindingMap[handle]; 314 pCI->mem = mem; 315 break; 316 } 317 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: { 318 auto pCI = &my_data->imageBindingMap[handle]; 319 pCI->mem = mem; 320 break; 321 } 322 default: 323 break; 324 } 325} 326 327static void add_object_create_info(layer_data *my_data, const uint64_t handle, const VkDebugReportObjectTypeEXT type, 328 const void *pCreateInfo) { 329 // TODO : For any CreateInfo struct that has ptrs, need to deep copy them and appropriately clean up on Destroy 330 switch (type) { 331 // Buffers and images are unique as their CreateInfo is in container struct 332 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: { 333 auto pCI = &my_data->bufferBindingMap[handle]; 334 memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO)); 335 memcpy(&pCI->create_info.buffer, pCreateInfo, sizeof(VkBufferCreateInfo)); 336 break; 337 } 338 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: { 339 auto pCI = &my_data->imageBindingMap[handle]; 340 memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO)); 341 memcpy(&pCI->create_info.image, pCreateInfo, sizeof(VkImageCreateInfo)); 342 break; 343 } 344 // Swap Chain is very unique, use my_data->imageBindingMap, but copy in 345 // SwapChainCreatInfo's usage flags and set the mem value to a unique key. These is used by 346 // vkCreateImageView and internal mem_tracker routines to distinguish swap chain images 347 case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: { 348 auto pCI = &my_data->imageBindingMap[handle]; 349 memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO)); 350 pCI->mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY; 351 pCI->valid = false; 352 pCI->create_info.image.usage = 353 const_cast<VkSwapchainCreateInfoKHR *>(static_cast<const VkSwapchainCreateInfoKHR *>(pCreateInfo))->imageUsage; 354 break; 355 } 356 default: 357 break; 358 } 359} 360 361// Add a fence, creating one if necessary to our list of fences/fenceIds 362static VkBool32 add_fence_info(layer_data *my_data, VkFence fence, VkQueue queue, uint64_t *fenceId) { 363 VkBool32 skipCall = VK_FALSE; 364 *fenceId = my_data->currentFenceId++; 365 366 // If no fence, create an internal fence to track the submissions 367 if (fence != VK_NULL_HANDLE) { 368 my_data->fenceMap[fence].fenceId = *fenceId; 369 my_data->fenceMap[fence].queue = queue; 370 // Validate that fence is in UNSIGNALED state 371 VkFenceCreateInfo *pFenceCI = &(my_data->fenceMap[fence].createInfo); 372 if (pFenceCI->flags & VK_FENCE_CREATE_SIGNALED_BIT) { 373 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 374 (uint64_t)fence, __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", 375 "Fence %#" PRIxLEAST64 " submitted in SIGNALED state. Fences must be reset before being submitted", 376 (uint64_t)fence); 377 } 378 } else { 379 // TODO : Do we need to create an internal fence here for tracking purposes? 380 } 381 // Update most recently submitted fence and fenceId for Queue 382 my_data->queueMap[queue].lastSubmittedId = *fenceId; 383 return skipCall; 384} 385 386// Remove a fenceInfo from our list of fences/fenceIds 387static void delete_fence_info(layer_data *my_data, VkFence fence) { my_data->fenceMap.erase(fence); } 388 389// Record information when a fence is known to be signalled 390static void update_fence_tracking(layer_data *my_data, VkFence fence) { 391 auto fence_item = my_data->fenceMap.find(fence); 392 if (fence_item != my_data->fenceMap.end()) { 393 FENCE_NODE *pCurFenceInfo = &(*fence_item).second; 394 VkQueue queue = pCurFenceInfo->queue; 395 auto queue_item = my_data->queueMap.find(queue); 396 if (queue_item != my_data->queueMap.end()) { 397 QUEUE_NODE *pQueueInfo = &(*queue_item).second; 398 if (pQueueInfo->lastRetiredId < pCurFenceInfo->fenceId) { 399 pQueueInfo->lastRetiredId = pCurFenceInfo->fenceId; 400 } 401 } 402 } 403 404 // Update fence state in fenceCreateInfo structure 405 auto pFCI = &(my_data->fenceMap[fence].createInfo); 406 pFCI->flags = static_cast<VkFenceCreateFlags>(pFCI->flags | VK_FENCE_CREATE_SIGNALED_BIT); 407} 408 409// Helper routine that updates the fence list for a specific queue to all-retired 410static void retire_queue_fences(layer_data *my_data, VkQueue queue) { 411 QUEUE_NODE *pQueueInfo = &my_data->queueMap[queue]; 412 // Set queue's lastRetired to lastSubmitted indicating all fences completed 413 pQueueInfo->lastRetiredId = pQueueInfo->lastSubmittedId; 414} 415 416// Helper routine that updates all queues to all-retired 417static void retire_device_fences(layer_data *my_data, VkDevice device) { 418 // Process each queue for device 419 // TODO: Add multiple device support 420 for (auto ii = my_data->queueMap.begin(); ii != my_data->queueMap.end(); ++ii) { 421 // Set queue's lastRetired to lastSubmitted indicating all fences completed 422 QUEUE_NODE *pQueueInfo = &(*ii).second; 423 pQueueInfo->lastRetiredId = pQueueInfo->lastSubmittedId; 424 } 425} 426 427// Helper function to validate correct usage bits set for buffers or images 428// Verify that (actual & desired) flags != 0 or, 429// if strict is true, verify that (actual & desired) flags == desired 430// In case of error, report it via dbg callbacks 431static VkBool32 validate_usage_flags(layer_data *my_data, void *disp_obj, VkFlags actual, VkFlags desired, VkBool32 strict, 432 uint64_t obj_handle, VkDebugReportObjectTypeEXT obj_type, char const *ty_str, 433 char const *func_name, char const *usage_str) { 434 VkBool32 correct_usage = VK_FALSE; 435 VkBool32 skipCall = VK_FALSE; 436 if (strict) 437 correct_usage = ((actual & desired) == desired); 438 else 439 correct_usage = ((actual & desired) != 0); 440 if (!correct_usage) { 441 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_type, obj_handle, __LINE__, 442 MEMTRACK_INVALID_USAGE_FLAG, "MEM", "Invalid usage flag for %s %#" PRIxLEAST64 443 " used by %s. In this case, %s should have %s set during creation.", 444 ty_str, obj_handle, func_name, ty_str, usage_str); 445 } 446 return skipCall; 447} 448 449// Helper function to validate usage flags for images 450// Pulls image info and then sends actual vs. desired usage off to helper above where 451// an error will be flagged if usage is not correct 452static VkBool32 validate_image_usage_flags(layer_data *my_data, void *disp_obj, VkImage image, VkFlags desired, VkBool32 strict, 453 char const *func_name, char const *usage_string) { 454 VkBool32 skipCall = VK_FALSE; 455 MT_OBJ_BINDING_INFO *pBindInfo = get_object_binding_info(my_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); 456 if (pBindInfo) { 457 skipCall = validate_usage_flags(my_data, disp_obj, pBindInfo->create_info.image.usage, desired, strict, (uint64_t)image, 458 VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "image", func_name, usage_string); 459 } 460 return skipCall; 461} 462 463// Helper function to validate usage flags for buffers 464// Pulls buffer info and then sends actual vs. desired usage off to helper above where 465// an error will be flagged if usage is not correct 466static VkBool32 validate_buffer_usage_flags(layer_data *my_data, void *disp_obj, VkBuffer buffer, VkFlags desired, VkBool32 strict, 467 char const *func_name, char const *usage_string) { 468 VkBool32 skipCall = VK_FALSE; 469 MT_OBJ_BINDING_INFO *pBindInfo = get_object_binding_info(my_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT); 470 if (pBindInfo) { 471 skipCall = validate_usage_flags(my_data, disp_obj, pBindInfo->create_info.buffer.usage, desired, strict, (uint64_t)buffer, 472 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "buffer", func_name, usage_string); 473 } 474 return skipCall; 475} 476 477// Return ptr to info in map container containing mem, or NULL if not found 478// Calls to this function should be wrapped in mutex 479static DEVICE_MEM_INFO *get_mem_obj_info(layer_data *dev_data, const VkDeviceMemory mem) { 480 auto item = dev_data->memObjMap.find(mem); 481 if (item != dev_data->memObjMap.end()) { 482 return &(*item).second; 483 } else { 484 return NULL; 485 } 486} 487 488static void add_mem_obj_info(layer_data *my_data, void *object, const VkDeviceMemory mem, 489 const VkMemoryAllocateInfo *pAllocateInfo) { 490 assert(object != NULL); 491 492 memcpy(&my_data->memObjMap[mem].allocInfo, pAllocateInfo, sizeof(VkMemoryAllocateInfo)); 493 // TODO: Update for real hardware, actually process allocation info structures 494 my_data->memObjMap[mem].allocInfo.pNext = NULL; 495 my_data->memObjMap[mem].object = object; 496 my_data->memObjMap[mem].refCount = 0; 497 my_data->memObjMap[mem].mem = mem; 498 my_data->memObjMap[mem].image = VK_NULL_HANDLE; 499 my_data->memObjMap[mem].memRange.offset = 0; 500 my_data->memObjMap[mem].memRange.size = 0; 501 my_data->memObjMap[mem].pData = 0; 502 my_data->memObjMap[mem].pDriverData = 0; 503 my_data->memObjMap[mem].valid = false; 504} 505 506static VkBool32 validate_memory_is_valid(layer_data *dev_data, VkDeviceMemory mem, const char *functionName, 507 VkImage image = VK_NULL_HANDLE) { 508 if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) { 509 MT_OBJ_BINDING_INFO *pBindInfo = 510 get_object_binding_info(dev_data, reinterpret_cast<const uint64_t &>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); 511 if (pBindInfo && !pBindInfo->valid) { 512 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 513 (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM", 514 "%s: Cannot read invalid swapchain image %" PRIx64 ", please fill the memory before using.", 515 functionName, (uint64_t)(image)); 516 } 517 } else { 518 DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem); 519 if (pMemObj && !pMemObj->valid) { 520 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 521 (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM", 522 "%s: Cannot read invalid memory %" PRIx64 ", please fill the memory before using.", functionName, 523 (uint64_t)(mem)); 524 } 525 } 526 return false; 527} 528 529static void set_memory_valid(layer_data *dev_data, VkDeviceMemory mem, bool valid, VkImage image = VK_NULL_HANDLE) { 530 if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) { 531 MT_OBJ_BINDING_INFO *pBindInfo = 532 get_object_binding_info(dev_data, reinterpret_cast<const uint64_t &>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); 533 if (pBindInfo) { 534 pBindInfo->valid = valid; 535 } 536 } else { 537 DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem); 538 if (pMemObj) { 539 pMemObj->valid = valid; 540 } 541 } 542} 543 544// Find CB Info and add mem reference to list container 545// Find Mem Obj Info and add CB reference to list container 546static VkBool32 update_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb, const VkDeviceMemory mem, 547 const char *apiName) { 548 VkBool32 skipCall = VK_FALSE; 549 550 // Skip validation if this image was created through WSI 551 if (mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) { 552 553 // First update CB binding in MemObj mini CB list 554 DEVICE_MEM_INFO *pMemInfo = get_mem_obj_info(dev_data, mem); 555 if (pMemInfo) { 556 // Search for cmd buffer object in memory object's binding list 557 VkBool32 found = VK_FALSE; 558 if (pMemInfo->pCommandBufferBindings.size() > 0) { 559 for (list<VkCommandBuffer>::iterator it = pMemInfo->pCommandBufferBindings.begin(); 560 it != pMemInfo->pCommandBufferBindings.end(); ++it) { 561 if ((*it) == cb) { 562 found = VK_TRUE; 563 break; 564 } 565 } 566 } 567 // If not present, add to list 568 if (found == VK_FALSE) { 569 pMemInfo->pCommandBufferBindings.push_front(cb); 570 pMemInfo->refCount++; 571 } 572 // Now update CBInfo's Mem reference list 573 GLOBAL_CB_NODE *pCBNode = getCBNode(dev_data, cb); 574 // TODO: keep track of all destroyed CBs so we know if this is a stale or simply invalid object 575 if (pCBNode) { 576 // Search for memory object in cmd buffer's reference list 577 VkBool32 found = VK_FALSE; 578 if (pCBNode->pMemObjList.size() > 0) { 579 for (auto it = pCBNode->pMemObjList.begin(); it != pCBNode->pMemObjList.end(); ++it) { 580 if ((*it) == mem) { 581 found = VK_TRUE; 582 break; 583 } 584 } 585 } 586 // If not present, add to list 587 if (found == VK_FALSE) { 588 pCBNode->pMemObjList.push_front(mem); 589 } 590 } 591 } 592 } 593 return skipCall; 594} 595 596// Free bindings related to CB 597static void clear_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb) { 598 GLOBAL_CB_NODE *pCBNode = getCBNode(dev_data, cb); 599 600 if (pCBNode) { 601 if (pCBNode->pMemObjList.size() > 0) { 602 list<VkDeviceMemory> mem_obj_list = pCBNode->pMemObjList; 603 for (list<VkDeviceMemory>::iterator it = mem_obj_list.begin(); it != mem_obj_list.end(); ++it) { 604 DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, *it); 605 if (pInfo) { 606 pInfo->pCommandBufferBindings.remove(cb); 607 pInfo->refCount--; 608 } 609 } 610 pCBNode->pMemObjList.clear(); 611 } 612 pCBNode->activeDescriptorSets.clear(); 613 pCBNode->validate_functions.clear(); 614 } 615} 616 617// Delete the entire CB list 618static void delete_cmd_buf_info_list(layer_data *my_data) { 619 for (auto &cb_node : my_data->commandBufferMap) { 620 clear_cmd_buf_and_mem_references(my_data, cb_node.first); 621 } 622 my_data->commandBufferMap.clear(); 623} 624 625// For given MemObjInfo, report Obj & CB bindings 626static VkBool32 reportMemReferencesAndCleanUp(layer_data *dev_data, DEVICE_MEM_INFO *pMemObjInfo) { 627 VkBool32 skipCall = VK_FALSE; 628 size_t cmdBufRefCount = pMemObjInfo->pCommandBufferBindings.size(); 629 size_t objRefCount = pMemObjInfo->pObjBindings.size(); 630 631 if ((pMemObjInfo->pCommandBufferBindings.size()) != 0) { 632 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 633 (uint64_t)pMemObjInfo->mem, __LINE__, MEMTRACK_FREED_MEM_REF, "MEM", 634 "Attempting to free memory object %#" PRIxLEAST64 " which still contains " PRINTF_SIZE_T_SPECIFIER 635 " references", 636 (uint64_t)pMemObjInfo->mem, (cmdBufRefCount + objRefCount)); 637 } 638 639 if (cmdBufRefCount > 0 && pMemObjInfo->pCommandBufferBindings.size() > 0) { 640 for (list<VkCommandBuffer>::const_iterator it = pMemObjInfo->pCommandBufferBindings.begin(); 641 it != pMemObjInfo->pCommandBufferBindings.end(); ++it) { 642 // TODO : CommandBuffer should be source Obj here 643 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 644 (uint64_t)(*it), __LINE__, MEMTRACK_FREED_MEM_REF, "MEM", 645 "Command Buffer %p still has a reference to mem obj %#" PRIxLEAST64, (*it), (uint64_t)pMemObjInfo->mem); 646 } 647 // Clear the list of hanging references 648 pMemObjInfo->pCommandBufferBindings.clear(); 649 } 650 651 if (objRefCount > 0 && pMemObjInfo->pObjBindings.size() > 0) { 652 for (auto it = pMemObjInfo->pObjBindings.begin(); it != pMemObjInfo->pObjBindings.end(); ++it) { 653 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, it->type, it->handle, __LINE__, 654 MEMTRACK_FREED_MEM_REF, "MEM", "VK Object %#" PRIxLEAST64 " still has a reference to mem obj %#" PRIxLEAST64, 655 it->handle, (uint64_t)pMemObjInfo->mem); 656 } 657 // Clear the list of hanging references 658 pMemObjInfo->pObjBindings.clear(); 659 } 660 return skipCall; 661} 662 663static VkBool32 deleteMemObjInfo(layer_data *my_data, void *object, VkDeviceMemory mem) { 664 VkBool32 skipCall = VK_FALSE; 665 auto item = my_data->memObjMap.find(mem); 666 if (item != my_data->memObjMap.end()) { 667 my_data->memObjMap.erase(item); 668 } else { 669 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 670 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM", 671 "Request to delete memory object %#" PRIxLEAST64 " not present in memory Object Map", (uint64_t)mem); 672 } 673 return skipCall; 674} 675 676// Check if fence for given CB is completed 677static bool checkCBCompleted(layer_data *my_data, const VkCommandBuffer cb, bool *complete) { 678 GLOBAL_CB_NODE *pCBNode = getCBNode(my_data, cb); 679 VkBool32 skipCall = false; 680 *complete = true; 681 682 if (pCBNode) { 683 if (pCBNode->lastSubmittedQueue != NULL) { 684 VkQueue queue = pCBNode->lastSubmittedQueue; 685 QUEUE_NODE *pQueueInfo = &my_data->queueMap[queue]; 686 if (pCBNode->fenceId > pQueueInfo->lastRetiredId) { 687 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 688 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)cb, __LINE__, MEMTRACK_NONE, "MEM", 689 "fence %#" PRIxLEAST64 " for CB %p has not been checked for completion", 690 (uint64_t)pCBNode->lastSubmittedFence, cb); 691 *complete = false; 692 } 693 } 694 } 695 return skipCall; 696} 697 698static VkBool32 freeMemObjInfo(layer_data *dev_data, void *object, VkDeviceMemory mem, VkBool32 internal) { 699 VkBool32 skipCall = VK_FALSE; 700 // Parse global list to find info w/ mem 701 DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem); 702 if (pInfo) { 703 if (pInfo->allocInfo.allocationSize == 0 && !internal) { 704 // TODO: Verify against Valid Use section 705 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 706 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM", 707 "Attempting to free memory associated with a Persistent Image, %#" PRIxLEAST64 ", " 708 "this should not be explicitly freed\n", 709 (uint64_t)mem); 710 } else { 711 // Clear any CB bindings for completed CBs 712 // TODO : Is there a better place to do this? 713 714 bool commandBufferComplete = false; 715 assert(pInfo->object != VK_NULL_HANDLE); 716 list<VkCommandBuffer>::iterator it = pInfo->pCommandBufferBindings.begin(); 717 list<VkCommandBuffer>::iterator temp; 718 while (pInfo->pCommandBufferBindings.size() > 0 && it != pInfo->pCommandBufferBindings.end()) { 719 skipCall |= checkCBCompleted(dev_data, *it, &commandBufferComplete); 720 if (commandBufferComplete) { 721 temp = it; 722 ++temp; 723 clear_cmd_buf_and_mem_references(dev_data, *it); 724 it = temp; 725 } else { 726 ++it; 727 } 728 } 729 730 // Now verify that no references to this mem obj remain and remove bindings 731 if (0 != pInfo->refCount) { 732 skipCall |= reportMemReferencesAndCleanUp(dev_data, pInfo); 733 } 734 // Delete mem obj info 735 skipCall |= deleteMemObjInfo(dev_data, object, mem); 736 } 737 } 738 return skipCall; 739} 740 741static const char *object_type_to_string(VkDebugReportObjectTypeEXT type) { 742 switch (type) { 743 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: 744 return "image"; 745 break; 746 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: 747 return "buffer"; 748 break; 749 case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: 750 return "swapchain"; 751 break; 752 default: 753 return "unknown"; 754 } 755} 756 757// Remove object binding performs 3 tasks: 758// 1. Remove ObjectInfo from MemObjInfo list container of obj bindings & free it 759// 2. Decrement refCount for MemObjInfo 760// 3. Clear mem binding for image/buffer by setting its handle to 0 761// TODO : This only applied to Buffer, Image, and Swapchain objects now, how should it be updated/customized? 762static VkBool32 clear_object_binding(layer_data *dev_data, void *dispObj, uint64_t handle, VkDebugReportObjectTypeEXT type) { 763 // TODO : Need to customize images/buffers/swapchains to track mem binding and clear it here appropriately 764 VkBool32 skipCall = VK_FALSE; 765 MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(dev_data, handle, type); 766 if (pObjBindInfo) { 767 DEVICE_MEM_INFO *pMemObjInfo = get_mem_obj_info(dev_data, pObjBindInfo->mem); 768 // TODO : Make sure this is a reasonable way to reset mem binding 769 pObjBindInfo->mem = VK_NULL_HANDLE; 770 if (pMemObjInfo) { 771 // This obj is bound to a memory object. Remove the reference to this object in that memory object's list, decrement the 772 // memObj's refcount 773 // and set the objects memory binding pointer to NULL. 774 VkBool32 clearSucceeded = VK_FALSE; 775 for (auto it = pMemObjInfo->pObjBindings.begin(); it != pMemObjInfo->pObjBindings.end(); ++it) { 776 if ((it->handle == handle) && (it->type == type)) { 777 pMemObjInfo->refCount--; 778 pMemObjInfo->pObjBindings.erase(it); 779 clearSucceeded = VK_TRUE; 780 break; 781 } 782 } 783 if (VK_FALSE == clearSucceeded) { 784 skipCall |= 785 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT, 786 "MEM", "While trying to clear mem binding for %s obj %#" PRIxLEAST64 787 ", unable to find that object referenced by mem obj %#" PRIxLEAST64, 788 object_type_to_string(type), handle, (uint64_t)pMemObjInfo->mem); 789 } 790 } 791 } 792 return skipCall; 793} 794 795// For NULL mem case, output warning 796// Make sure given object is in global object map 797// IF a previous binding existed, output validation error 798// Otherwise, add reference from objectInfo to memoryInfo 799// Add reference off of objInfo 800// device is required for error logging, need a dispatchable 801// object for that. 802static VkBool32 set_mem_binding(layer_data *dev_data, void *dispatch_object, VkDeviceMemory mem, uint64_t handle, 803 VkDebugReportObjectTypeEXT type, const char *apiName) { 804 VkBool32 skipCall = VK_FALSE; 805 // Handle NULL case separately, just clear previous binding & decrement reference 806 if (mem == VK_NULL_HANDLE) { 807 // TODO: Verify against Valid Use section of spec. 808 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_MEM_OBJ, 809 "MEM", "In %s, attempting to Bind Obj(%#" PRIxLEAST64 ") to NULL", apiName, handle); 810 } else { 811 MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(dev_data, handle, type); 812 if (!pObjBindInfo) { 813 skipCall |= 814 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS, 815 "MEM", "In %s, attempting to update Binding of %s Obj(%#" PRIxLEAST64 ") that's not in global list()", 816 object_type_to_string(type), apiName, handle); 817 } else { 818 // non-null case so should have real mem obj 819 DEVICE_MEM_INFO *pMemInfo = get_mem_obj_info(dev_data, mem); 820 if (pMemInfo) { 821 // TODO : Need to track mem binding for obj and report conflict here 822 DEVICE_MEM_INFO *pPrevBinding = get_mem_obj_info(dev_data, pObjBindInfo->mem); 823 if (pPrevBinding != NULL) { 824 skipCall |= 825 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 826 (uint64_t)mem, __LINE__, MEMTRACK_REBIND_OBJECT, "MEM", 827 "In %s, attempting to bind memory (%#" PRIxLEAST64 ") to object (%#" PRIxLEAST64 828 ") which has already been bound to mem object %#" PRIxLEAST64, 829 apiName, (uint64_t)mem, handle, (uint64_t)pPrevBinding->mem); 830 } else { 831 MT_OBJ_HANDLE_TYPE oht; 832 oht.handle = handle; 833 oht.type = type; 834 pMemInfo->pObjBindings.push_front(oht); 835 pMemInfo->refCount++; 836 // For image objects, make sure default memory state is correctly set 837 // TODO : What's the best/correct way to handle this? 838 if (VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT == type) { 839 VkImageCreateInfo ici = pObjBindInfo->create_info.image; 840 if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { 841 // TODO:: More memory state transition stuff. 842 } 843 } 844 pObjBindInfo->mem = mem; 845 } 846 } 847 } 848 } 849 return skipCall; 850} 851 852// For NULL mem case, clear any previous binding Else... 853// Make sure given object is in its object map 854// IF a previous binding existed, update binding 855// Add reference from objectInfo to memoryInfo 856// Add reference off of object's binding info 857// Return VK_TRUE if addition is successful, VK_FALSE otherwise 858static VkBool32 set_sparse_mem_binding(layer_data *dev_data, void *dispObject, VkDeviceMemory mem, uint64_t handle, 859 VkDebugReportObjectTypeEXT type, const char *apiName) { 860 VkBool32 skipCall = VK_FALSE; 861 // Handle NULL case separately, just clear previous binding & decrement reference 862 if (mem == VK_NULL_HANDLE) { 863 skipCall = clear_object_binding(dev_data, dispObject, handle, type); 864 } else { 865 MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(dev_data, handle, type); 866 if (!pObjBindInfo) { 867 skipCall |= log_msg( 868 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS, "MEM", 869 "In %s, attempting to update Binding of Obj(%#" PRIxLEAST64 ") that's not in global list()", apiName, handle); 870 } 871 // non-null case so should have real mem obj 872 DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem); 873 if (pInfo) { 874 // Search for object in memory object's binding list 875 VkBool32 found = VK_FALSE; 876 if (pInfo->pObjBindings.size() > 0) { 877 for (auto it = pInfo->pObjBindings.begin(); it != pInfo->pObjBindings.end(); ++it) { 878 if (((*it).handle == handle) && ((*it).type == type)) { 879 found = VK_TRUE; 880 break; 881 } 882 } 883 } 884 // If not present, add to list 885 if (found == VK_FALSE) { 886 MT_OBJ_HANDLE_TYPE oht; 887 oht.handle = handle; 888 oht.type = type; 889 pInfo->pObjBindings.push_front(oht); 890 pInfo->refCount++; 891 } 892 // Need to set mem binding for this object 893 pObjBindInfo->mem = mem; 894 } 895 } 896 return skipCall; 897} 898 899template <typename T> 900void print_object_map_members(layer_data *my_data, void *dispObj, T const &objectName, VkDebugReportObjectTypeEXT objectType, 901 const char *objectStr) { 902 for (auto const &element : objectName) { 903 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objectType, 0, __LINE__, MEMTRACK_NONE, "MEM", 904 " %s Object list contains %s Object %#" PRIxLEAST64 " ", objectStr, objectStr, element.first); 905 } 906} 907 908// For given Object, get 'mem' obj that it's bound to or NULL if no binding 909static VkBool32 get_mem_binding_from_object(layer_data *my_data, void *dispObj, const uint64_t handle, 910 const VkDebugReportObjectTypeEXT type, VkDeviceMemory *mem) { 911 VkBool32 skipCall = VK_FALSE; 912 *mem = VK_NULL_HANDLE; 913 MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(my_data, handle, type); 914 if (pObjBindInfo) { 915 if (pObjBindInfo->mem) { 916 *mem = pObjBindInfo->mem; 917 } else { 918 skipCall = 919 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS, 920 "MEM", "Trying to get mem binding for object %#" PRIxLEAST64 " but object has no mem binding", handle); 921 } 922 } else { 923 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT, 924 "MEM", "Trying to get mem binding for object %#" PRIxLEAST64 " but no such object in %s list", handle, 925 object_type_to_string(type)); 926 } 927 return skipCall; 928} 929 930// Print details of MemObjInfo list 931static void print_mem_list(layer_data *dev_data, void *dispObj) { 932 DEVICE_MEM_INFO *pInfo = NULL; 933 934 // Early out if info is not requested 935 if (!(dev_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) { 936 return; 937 } 938 939 // Just printing each msg individually for now, may want to package these into single large print 940 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, 941 MEMTRACK_NONE, "MEM", "Details of Memory Object list (of size " PRINTF_SIZE_T_SPECIFIER " elements)", 942 dev_data->memObjMap.size()); 943 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, 944 MEMTRACK_NONE, "MEM", "============================="); 945 946 if (dev_data->memObjMap.size() <= 0) 947 return; 948 949 for (auto ii = dev_data->memObjMap.begin(); ii != dev_data->memObjMap.end(); ++ii) { 950 pInfo = &(*ii).second; 951 952 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 953 __LINE__, MEMTRACK_NONE, "MEM", " ===MemObjInfo at %p===", (void *)pInfo); 954 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 955 __LINE__, MEMTRACK_NONE, "MEM", " Mem object: %#" PRIxLEAST64, (uint64_t)(pInfo->mem)); 956 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 957 __LINE__, MEMTRACK_NONE, "MEM", " Ref Count: %u", pInfo->refCount); 958 if (0 != pInfo->allocInfo.allocationSize) { 959 string pAllocInfoMsg = vk_print_vkmemoryallocateinfo(&pInfo->allocInfo, "MEM(INFO): "); 960 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 961 __LINE__, MEMTRACK_NONE, "MEM", " Mem Alloc info:\n%s", pAllocInfoMsg.c_str()); 962 } else { 963 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 964 __LINE__, MEMTRACK_NONE, "MEM", " Mem Alloc info is NULL (alloc done by vkCreateSwapchainKHR())"); 965 } 966 967 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 968 __LINE__, MEMTRACK_NONE, "MEM", " VK OBJECT Binding list of size " PRINTF_SIZE_T_SPECIFIER " elements:", 969 pInfo->pObjBindings.size()); 970 if (pInfo->pObjBindings.size() > 0) { 971 for (list<MT_OBJ_HANDLE_TYPE>::iterator it = pInfo->pObjBindings.begin(); it != pInfo->pObjBindings.end(); ++it) { 972 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 973 0, __LINE__, MEMTRACK_NONE, "MEM", " VK OBJECT %" PRIu64, it->handle); 974 } 975 } 976 977 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 978 __LINE__, MEMTRACK_NONE, "MEM", 979 " VK Command Buffer (CB) binding list of size " PRINTF_SIZE_T_SPECIFIER " elements", 980 pInfo->pCommandBufferBindings.size()); 981 if (pInfo->pCommandBufferBindings.size() > 0) { 982 for (list<VkCommandBuffer>::iterator it = pInfo->pCommandBufferBindings.begin(); 983 it != pInfo->pCommandBufferBindings.end(); ++it) { 984 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 985 0, __LINE__, MEMTRACK_NONE, "MEM", " VK CB %p", (*it)); 986 } 987 } 988 } 989} 990 991static void printCBList(layer_data *my_data, void *dispObj) { 992 GLOBAL_CB_NODE *pCBInfo = NULL; 993 994 // Early out if info is not requested 995 if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) { 996 return; 997 } 998 999 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, 1000 MEMTRACK_NONE, "MEM", "Details of CB list (of size " PRINTF_SIZE_T_SPECIFIER " elements)", 1001 my_data->commandBufferMap.size()); 1002 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, 1003 MEMTRACK_NONE, "MEM", "=================="); 1004 1005 if (my_data->commandBufferMap.size() <= 0) 1006 return; 1007 1008 for (auto &cb_node : my_data->commandBufferMap) { 1009 pCBInfo = cb_node.second; 1010 1011 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 1012 __LINE__, MEMTRACK_NONE, "MEM", " CB Info (%p) has CB %p, fenceId %" PRIx64 ", and fence %#" PRIxLEAST64, 1013 (void *)pCBInfo, (void *)pCBInfo->commandBuffer, pCBInfo->fenceId, (uint64_t)pCBInfo->lastSubmittedFence); 1014 1015 if (pCBInfo->pMemObjList.size() <= 0) 1016 continue; 1017 for (list<VkDeviceMemory>::iterator it = pCBInfo->pMemObjList.begin(); it != pCBInfo->pMemObjList.end(); ++it) { 1018 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 1019 __LINE__, MEMTRACK_NONE, "MEM", " Mem obj %" PRIu64, (uint64_t)(*it)); 1020 } 1021 } 1022} 1023 1024#endif 1025 1026// Map actual TID to an index value and return that index 1027// This keeps TIDs in range from 0-MAX_TID and simplifies compares between runs 1028static uint32_t getTIDIndex() { 1029 loader_platform_thread_id tid = loader_platform_get_thread_id(); 1030 for (uint32_t i = 0; i < g_maxTID; i++) { 1031 if (tid == g_tidMapping[i]) 1032 return i; 1033 } 1034 // Don't yet have mapping, set it and return newly set index 1035 uint32_t retVal = (uint32_t)g_maxTID; 1036 g_tidMapping[g_maxTID++] = tid; 1037 assert(g_maxTID < MAX_TID); 1038 return retVal; 1039} 1040 1041// Return a string representation of CMD_TYPE enum 1042static string cmdTypeToString(CMD_TYPE cmd) { 1043 switch (cmd) { 1044 case CMD_BINDPIPELINE: 1045 return "CMD_BINDPIPELINE"; 1046 case CMD_BINDPIPELINEDELTA: 1047 return "CMD_BINDPIPELINEDELTA"; 1048 case CMD_SETVIEWPORTSTATE: 1049 return "CMD_SETVIEWPORTSTATE"; 1050 case CMD_SETLINEWIDTHSTATE: 1051 return "CMD_SETLINEWIDTHSTATE"; 1052 case CMD_SETDEPTHBIASSTATE: 1053 return "CMD_SETDEPTHBIASSTATE"; 1054 case CMD_SETBLENDSTATE: 1055 return "CMD_SETBLENDSTATE"; 1056 case CMD_SETDEPTHBOUNDSSTATE: 1057 return "CMD_SETDEPTHBOUNDSSTATE"; 1058 case CMD_SETSTENCILREADMASKSTATE: 1059 return "CMD_SETSTENCILREADMASKSTATE"; 1060 case CMD_SETSTENCILWRITEMASKSTATE: 1061 return "CMD_SETSTENCILWRITEMASKSTATE"; 1062 case CMD_SETSTENCILREFERENCESTATE: 1063 return "CMD_SETSTENCILREFERENCESTATE"; 1064 case CMD_BINDDESCRIPTORSETS: 1065 return "CMD_BINDDESCRIPTORSETS"; 1066 case CMD_BINDINDEXBUFFER: 1067 return "CMD_BINDINDEXBUFFER"; 1068 case CMD_BINDVERTEXBUFFER: 1069 return "CMD_BINDVERTEXBUFFER"; 1070 case CMD_DRAW: 1071 return "CMD_DRAW"; 1072 case CMD_DRAWINDEXED: 1073 return "CMD_DRAWINDEXED"; 1074 case CMD_DRAWINDIRECT: 1075 return "CMD_DRAWINDIRECT"; 1076 case CMD_DRAWINDEXEDINDIRECT: 1077 return "CMD_DRAWINDEXEDINDIRECT"; 1078 case CMD_DISPATCH: 1079 return "CMD_DISPATCH"; 1080 case CMD_DISPATCHINDIRECT: 1081 return "CMD_DISPATCHINDIRECT"; 1082 case CMD_COPYBUFFER: 1083 return "CMD_COPYBUFFER"; 1084 case CMD_COPYIMAGE: 1085 return "CMD_COPYIMAGE"; 1086 case CMD_BLITIMAGE: 1087 return "CMD_BLITIMAGE"; 1088 case CMD_COPYBUFFERTOIMAGE: 1089 return "CMD_COPYBUFFERTOIMAGE"; 1090 case CMD_COPYIMAGETOBUFFER: 1091 return "CMD_COPYIMAGETOBUFFER"; 1092 case CMD_CLONEIMAGEDATA: 1093 return "CMD_CLONEIMAGEDATA"; 1094 case CMD_UPDATEBUFFER: 1095 return "CMD_UPDATEBUFFER"; 1096 case CMD_FILLBUFFER: 1097 return "CMD_FILLBUFFER"; 1098 case CMD_CLEARCOLORIMAGE: 1099 return "CMD_CLEARCOLORIMAGE"; 1100 case CMD_CLEARATTACHMENTS: 1101 return "CMD_CLEARCOLORATTACHMENT"; 1102 case CMD_CLEARDEPTHSTENCILIMAGE: 1103 return "CMD_CLEARDEPTHSTENCILIMAGE"; 1104 case CMD_RESOLVEIMAGE: 1105 return "CMD_RESOLVEIMAGE"; 1106 case CMD_SETEVENT: 1107 return "CMD_SETEVENT"; 1108 case CMD_RESETEVENT: 1109 return "CMD_RESETEVENT"; 1110 case CMD_WAITEVENTS: 1111 return "CMD_WAITEVENTS"; 1112 case CMD_PIPELINEBARRIER: 1113 return "CMD_PIPELINEBARRIER"; 1114 case CMD_BEGINQUERY: 1115 return "CMD_BEGINQUERY"; 1116 case CMD_ENDQUERY: 1117 return "CMD_ENDQUERY"; 1118 case CMD_RESETQUERYPOOL: 1119 return "CMD_RESETQUERYPOOL"; 1120 case CMD_COPYQUERYPOOLRESULTS: 1121 return "CMD_COPYQUERYPOOLRESULTS"; 1122 case CMD_WRITETIMESTAMP: 1123 return "CMD_WRITETIMESTAMP"; 1124 case CMD_INITATOMICCOUNTERS: 1125 return "CMD_INITATOMICCOUNTERS"; 1126 case CMD_LOADATOMICCOUNTERS: 1127 return "CMD_LOADATOMICCOUNTERS"; 1128 case CMD_SAVEATOMICCOUNTERS: 1129 return "CMD_SAVEATOMICCOUNTERS"; 1130 case CMD_BEGINRENDERPASS: 1131 return "CMD_BEGINRENDERPASS"; 1132 case CMD_ENDRENDERPASS: 1133 return "CMD_ENDRENDERPASS"; 1134 default: 1135 return "UNKNOWN"; 1136 } 1137} 1138 1139// SPIRV utility functions 1140static void build_def_index(shader_module *module) { 1141 for (auto insn : *module) { 1142 switch (insn.opcode()) { 1143 /* Types */ 1144 case spv::OpTypeVoid: 1145 case spv::OpTypeBool: 1146 case spv::OpTypeInt: 1147 case spv::OpTypeFloat: 1148 case spv::OpTypeVector: 1149 case spv::OpTypeMatrix: 1150 case spv::OpTypeImage: 1151 case spv::OpTypeSampler: 1152 case spv::OpTypeSampledImage: 1153 case spv::OpTypeArray: 1154 case spv::OpTypeRuntimeArray: 1155 case spv::OpTypeStruct: 1156 case spv::OpTypeOpaque: 1157 case spv::OpTypePointer: 1158 case spv::OpTypeFunction: 1159 case spv::OpTypeEvent: 1160 case spv::OpTypeDeviceEvent: 1161 case spv::OpTypeReserveId: 1162 case spv::OpTypeQueue: 1163 case spv::OpTypePipe: 1164 module->def_index[insn.word(1)] = insn.offset(); 1165 break; 1166 1167 /* Fixed constants */ 1168 case spv::OpConstantTrue: 1169 case spv::OpConstantFalse: 1170 case spv::OpConstant: 1171 case spv::OpConstantComposite: 1172 case spv::OpConstantSampler: 1173 case spv::OpConstantNull: 1174 module->def_index[insn.word(2)] = insn.offset(); 1175 break; 1176 1177 /* Specialization constants */ 1178 case spv::OpSpecConstantTrue: 1179 case spv::OpSpecConstantFalse: 1180 case spv::OpSpecConstant: 1181 case spv::OpSpecConstantComposite: 1182 case spv::OpSpecConstantOp: 1183 module->def_index[insn.word(2)] = insn.offset(); 1184 break; 1185 1186 /* Variables */ 1187 case spv::OpVariable: 1188 module->def_index[insn.word(2)] = insn.offset(); 1189 break; 1190 1191 /* Functions */ 1192 case spv::OpFunction: 1193 module->def_index[insn.word(2)] = insn.offset(); 1194 break; 1195 1196 default: 1197 /* We don't care about any other defs for now. */ 1198 break; 1199 } 1200 } 1201} 1202 1203static spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) { 1204 for (auto insn : *src) { 1205 if (insn.opcode() == spv::OpEntryPoint) { 1206 auto entrypointName = (char const *)&insn.word(3); 1207 auto entrypointStageBits = 1u << insn.word(1); 1208 1209 if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) { 1210 return insn; 1211 } 1212 } 1213 } 1214 1215 return src->end(); 1216} 1217 1218bool shader_is_spirv(VkShaderModuleCreateInfo const *pCreateInfo) { 1219 uint32_t *words = (uint32_t *)pCreateInfo->pCode; 1220 size_t sizeInWords = pCreateInfo->codeSize / sizeof(uint32_t); 1221 1222 /* Just validate that the header makes sense. */ 1223 return sizeInWords >= 5 && words[0] == spv::MagicNumber && words[1] == spv::Version; 1224} 1225 1226static char const *storage_class_name(unsigned sc) { 1227 switch (sc) { 1228 case spv::StorageClassInput: 1229 return "input"; 1230 case spv::StorageClassOutput: 1231 return "output"; 1232 case spv::StorageClassUniformConstant: 1233 return "const uniform"; 1234 case spv::StorageClassUniform: 1235 return "uniform"; 1236 case spv::StorageClassWorkgroup: 1237 return "workgroup local"; 1238 case spv::StorageClassCrossWorkgroup: 1239 return "workgroup global"; 1240 case spv::StorageClassPrivate: 1241 return "private global"; 1242 case spv::StorageClassFunction: 1243 return "function"; 1244 case spv::StorageClassGeneric: 1245 return "generic"; 1246 case spv::StorageClassAtomicCounter: 1247 return "atomic counter"; 1248 case spv::StorageClassImage: 1249 return "image"; 1250 case spv::StorageClassPushConstant: 1251 return "push constant"; 1252 default: 1253 return "unknown"; 1254 } 1255} 1256 1257/* get the value of an integral constant */ 1258unsigned get_constant_value(shader_module const *src, unsigned id) { 1259 auto value = src->get_def(id); 1260 assert(value != src->end()); 1261 1262 if (value.opcode() != spv::OpConstant) { 1263 /* TODO: Either ensure that the specialization transform is already performed on a module we're 1264 considering here, OR -- specialize on the fly now. 1265 */ 1266 return 1; 1267 } 1268 1269 return value.word(3); 1270} 1271 1272 1273static void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) { 1274 auto insn = src->get_def(type); 1275 assert(insn != src->end()); 1276 1277 switch (insn.opcode()) { 1278 case spv::OpTypeBool: 1279 ss << "bool"; 1280 break; 1281 case spv::OpTypeInt: 1282 ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2); 1283 break; 1284 case spv::OpTypeFloat: 1285 ss << "float" << insn.word(2); 1286 break; 1287 case spv::OpTypeVector: 1288 ss << "vec" << insn.word(3) << " of "; 1289 describe_type_inner(ss, src, insn.word(2)); 1290 break; 1291 case spv::OpTypeMatrix: 1292 ss << "mat" << insn.word(3) << " of "; 1293 describe_type_inner(ss, src, insn.word(2)); 1294 break; 1295 case spv::OpTypeArray: 1296 ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of "; 1297 describe_type_inner(ss, src, insn.word(2)); 1298 break; 1299 case spv::OpTypePointer: 1300 ss << "ptr to " << storage_class_name(insn.word(2)) << " "; 1301 describe_type_inner(ss, src, insn.word(3)); 1302 break; 1303 case spv::OpTypeStruct: { 1304 ss << "struct of ("; 1305 for (unsigned i = 2; i < insn.len(); i++) { 1306 describe_type_inner(ss, src, insn.word(i)); 1307 if (i == insn.len() - 1) { 1308 ss << ")"; 1309 } else { 1310 ss << ", "; 1311 } 1312 } 1313 break; 1314 } 1315 case spv::OpTypeSampler: 1316 ss << "sampler"; 1317 break; 1318 case spv::OpTypeSampledImage: 1319 ss << "sampler+"; 1320 describe_type_inner(ss, src, insn.word(2)); 1321 break; 1322 case spv::OpTypeImage: 1323 ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")"; 1324 break; 1325 default: 1326 ss << "oddtype"; 1327 break; 1328 } 1329} 1330 1331 1332static std::string describe_type(shader_module const *src, unsigned type) { 1333 std::ostringstream ss; 1334 describe_type_inner(ss, src, type); 1335 return ss.str(); 1336} 1337 1338 1339static bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool b_arrayed) { 1340 /* walk two type trees together, and complain about differences */ 1341 auto a_insn = a->get_def(a_type); 1342 auto b_insn = b->get_def(b_type); 1343 assert(a_insn != a->end()); 1344 assert(b_insn != b->end()); 1345 1346 if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) { 1347 /* we probably just found the extra level of arrayness in b_type: compare the type inside it to a_type */ 1348 return types_match(a, b, a_type, b_insn.word(2), false); 1349 } 1350 1351 if (a_insn.opcode() != b_insn.opcode()) { 1352 return false; 1353 } 1354 1355 switch (a_insn.opcode()) { 1356 /* if b_arrayed and we hit a leaf type, then we can't match -- there's nowhere for the extra OpTypeArray to be! */ 1357 case spv::OpTypeBool: 1358 return true && !b_arrayed; 1359 case spv::OpTypeInt: 1360 /* match on width, signedness */ 1361 return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3) && !b_arrayed; 1362 case spv::OpTypeFloat: 1363 /* match on width */ 1364 return a_insn.word(2) == b_insn.word(2) && !b_arrayed; 1365 case spv::OpTypeVector: 1366 case spv::OpTypeMatrix: 1367 /* match on element type, count. these all have the same layout. we don't get here if 1368 * b_arrayed -- that is handled above. */ 1369 return !b_arrayed && types_match(a, b, a_insn.word(2), b_insn.word(2), b_arrayed) && a_insn.word(3) == b_insn.word(3); 1370 case spv::OpTypeArray: 1371 /* match on element type, count. these all have the same layout. we don't get here if 1372 * b_arrayed. This differs from vector & matrix types in that the array size is the id of a constant instruction, 1373 * not a literal within OpTypeArray */ 1374 return !b_arrayed && types_match(a, b, a_insn.word(2), b_insn.word(2), b_arrayed) && 1375 get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3)); 1376 case spv::OpTypeStruct: 1377 /* match on all element types */ 1378 { 1379 if (b_arrayed) { 1380 /* for the purposes of matching different levels of arrayness, structs are leaves. */ 1381 return false; 1382 } 1383 1384 if (a_insn.len() != b_insn.len()) { 1385 return false; /* structs cannot match if member counts differ */ 1386 } 1387 1388 for (unsigned i = 2; i < a_insn.len(); i++) { 1389 if (!types_match(a, b, a_insn.word(i), b_insn.word(i), b_arrayed)) { 1390 return false; 1391 } 1392 } 1393 1394 return true; 1395 } 1396 case spv::OpTypePointer: 1397 /* match on pointee type. storage class is expected to differ */ 1398 return types_match(a, b, a_insn.word(3), b_insn.word(3), b_arrayed); 1399 1400 default: 1401 /* remaining types are CLisms, or may not appear in the interfaces we 1402 * are interested in. Just claim no match. 1403 */ 1404 return false; 1405 } 1406} 1407 1408static int value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def) { 1409 auto it = map.find(id); 1410 if (it == map.end()) 1411 return def; 1412 else 1413 return it->second; 1414} 1415 1416static unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) { 1417 auto insn = src->get_def(type); 1418 assert(insn != src->end()); 1419 1420 switch (insn.opcode()) { 1421 case spv::OpTypePointer: 1422 /* see through the ptr -- this is only ever at the toplevel for graphics shaders; 1423 * we're never actually passing pointers around. */ 1424 return get_locations_consumed_by_type(src, insn.word(3), strip_array_level); 1425 case spv::OpTypeArray: 1426 if (strip_array_level) { 1427 return get_locations_consumed_by_type(src, insn.word(2), false); 1428 } else { 1429 return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false); 1430 } 1431 case spv::OpTypeMatrix: 1432 /* num locations is the dimension * element size */ 1433 return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false); 1434 default: 1435 /* everything else is just 1. */ 1436 return 1; 1437 1438 /* TODO: extend to handle 64bit scalar types, whose vectors may need 1439 * multiple locations. */ 1440 } 1441} 1442 1443typedef std::pair<unsigned, unsigned> location_t; 1444typedef std::pair<unsigned, unsigned> descriptor_slot_t; 1445 1446struct interface_var { 1447 uint32_t id; 1448 uint32_t type_id; 1449 uint32_t offset; 1450 /* TODO: collect the name, too? Isn't required to be present. */ 1451}; 1452 1453static spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) { 1454 while (true) { 1455 1456 if (def.opcode() == spv::OpTypePointer) { 1457 def = src->get_def(def.word(3)); 1458 } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) { 1459 def = src->get_def(def.word(2)); 1460 is_array_of_verts = false; 1461 } else if (def.opcode() == spv::OpTypeStruct) { 1462 return def; 1463 } else { 1464 return src->end(); 1465 } 1466 } 1467} 1468 1469static void collect_interface_block_members(layer_data *my_data, VkDevice dev, shader_module const *src, 1470 std::map<location_t, interface_var> &out, 1471 std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts, 1472 uint32_t id, uint32_t type_id) { 1473 /* Walk down the type_id presented, trying to determine whether it's actually an interface block. */ 1474 auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts); 1475 if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) { 1476 /* this isn't an interface block. */ 1477 return; 1478 } 1479 1480 std::unordered_map<unsigned, unsigned> member_components; 1481 1482 /* Walk all the OpMemberDecorate for type's result id -- first pass, collect components. */ 1483 for (auto insn : *src) { 1484 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) { 1485 unsigned member_index = insn.word(2); 1486 1487 if (insn.word(3) == spv::DecorationComponent) { 1488 unsigned component = insn.word(4); 1489 member_components[member_index] = component; 1490 } 1491 } 1492 } 1493 1494 /* Second pass -- produce the output, from Location decorations */ 1495 for (auto insn : *src) { 1496 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) { 1497 unsigned member_index = insn.word(2); 1498 unsigned member_type_id = type.word(2 + member_index); 1499 1500 if (insn.word(3) == spv::DecorationLocation) { 1501 unsigned location = insn.word(4); 1502 unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false); 1503 auto component_it = member_components.find(member_index); 1504 unsigned component = component_it == member_components.end() ? 0 : component_it->second; 1505 1506 for (unsigned int offset = 0; offset < num_locations; offset++) { 1507 interface_var v; 1508 v.id = id; 1509 /* TODO: member index in interface_var too? */ 1510 v.type_id = member_type_id; 1511 v.offset = offset; 1512 out[std::make_pair(location + offset, component)] = v; 1513 } 1514 } 1515 } 1516 } 1517} 1518 1519static void collect_interface_by_location(layer_data *my_data, VkDevice dev, shader_module const *src, spirv_inst_iter entrypoint, 1520 spv::StorageClass sinterface, std::map<location_t, interface_var> &out, 1521 bool is_array_of_verts) { 1522 std::unordered_map<unsigned, unsigned> var_locations; 1523 std::unordered_map<unsigned, unsigned> var_builtins; 1524 std::unordered_map<unsigned, unsigned> var_components; 1525 std::unordered_map<unsigned, unsigned> blocks; 1526 1527 for (auto insn : *src) { 1528 1529 /* We consider two interface models: SSO rendezvous-by-location, and 1530 * builtins. Complain about anything that fits neither model. 1531 */ 1532 if (insn.opcode() == spv::OpDecorate) { 1533 if (insn.word(2) == spv::DecorationLocation) { 1534 var_locations[insn.word(1)] = insn.word(3); 1535 } 1536 1537 if (insn.word(2) == spv::DecorationBuiltIn) { 1538 var_builtins[insn.word(1)] = insn.word(3); 1539 } 1540 1541 if (insn.word(2) == spv::DecorationComponent) { 1542 var_components[insn.word(1)] = insn.word(3); 1543 } 1544 1545 if (insn.word(2) == spv::DecorationBlock) { 1546 blocks[insn.word(1)] = 1; 1547 } 1548 } 1549 } 1550 1551 /* TODO: handle grouped decorations */ 1552 /* TODO: handle index=1 dual source outputs from FS -- two vars will 1553 * have the same location, and we DONT want to clobber. */ 1554 1555 /* find the end of the entrypoint's name string. additional zero bytes follow the actual null 1556 terminator, to fill out the rest of the word - so we only need to look at the last byte in 1557 the word to determine which word contains the terminator. */ 1558 auto word = 3; 1559 while (entrypoint.word(word) & 0xff000000u) { 1560 ++word; 1561 } 1562 ++word; 1563 1564 for (; word < entrypoint.len(); word++) { 1565 auto insn = src->get_def(entrypoint.word(word)); 1566 assert(insn != src->end()); 1567 assert(insn.opcode() == spv::OpVariable); 1568 1569 if (insn.word(3) == sinterface) { 1570 unsigned id = insn.word(2); 1571 unsigned type = insn.word(1); 1572 1573 int location = value_or_default(var_locations, id, -1); 1574 int builtin = value_or_default(var_builtins, id, -1); 1575 unsigned component = value_or_default(var_components, id, 0); /* unspecified is OK, is 0 */ 1576 1577 /* All variables and interface block members in the Input or Output storage classes 1578 * must be decorated with either a builtin or an explicit location. 1579 * 1580 * TODO: integrate the interface block support here. For now, don't complain -- 1581 * a valid SPIRV module will only hit this path for the interface block case, as the 1582 * individual members of the type are decorated, rather than variable declarations. 1583 */ 1584 1585 if (location != -1) { 1586 /* A user-defined interface variable, with a location. Where a variable 1587 * occupied multiple locations, emit one result for each. */ 1588 unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts); 1589 for (unsigned int offset = 0; offset < num_locations; offset++) { 1590 interface_var v; 1591 v.id = id; 1592 v.type_id = type; 1593 v.offset = offset; 1594 out[std::make_pair(location + offset, component)] = v; 1595 } 1596 } else if (builtin == -1) { 1597 /* An interface block instance */ 1598 collect_interface_block_members(my_data, dev, src, out, blocks, is_array_of_verts, id, type); 1599 } 1600 } 1601 } 1602} 1603 1604static void collect_interface_by_descriptor_slot(layer_data *my_data, VkDevice dev, shader_module const *src, 1605 std::unordered_set<uint32_t> const &accessible_ids, 1606 std::map<descriptor_slot_t, interface_var> &out) { 1607 1608 std::unordered_map<unsigned, unsigned> var_sets; 1609 std::unordered_map<unsigned, unsigned> var_bindings; 1610 1611 for (auto insn : *src) { 1612 /* All variables in the Uniform or UniformConstant storage classes are required to be decorated with both 1613 * DecorationDescriptorSet and DecorationBinding. 1614 */ 1615 if (insn.opcode() == spv::OpDecorate) { 1616 if (insn.word(2) == spv::DecorationDescriptorSet) { 1617 var_sets[insn.word(1)] = insn.word(3); 1618 } 1619 1620 if (insn.word(2) == spv::DecorationBinding) { 1621 var_bindings[insn.word(1)] = insn.word(3); 1622 } 1623 } 1624 } 1625 1626 for (auto id : accessible_ids) { 1627 auto insn = src->get_def(id); 1628 assert(insn != src->end()); 1629 1630 if (insn.opcode() == spv::OpVariable && 1631 (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) { 1632 unsigned set = value_or_default(var_sets, insn.word(2), 0); 1633 unsigned binding = value_or_default(var_bindings, insn.word(2), 0); 1634 1635 auto existing_it = out.find(std::make_pair(set, binding)); 1636 if (existing_it != out.end()) { 1637 /* conflict within spv image */ 1638 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1639 __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC", 1640 "var %d (type %d) in %s interface in descriptor slot (%u,%u) conflicts with existing definition", 1641 insn.word(2), insn.word(1), storage_class_name(insn.word(3)), existing_it->first.first, 1642 existing_it->first.second); 1643 } 1644 1645 interface_var v; 1646 v.id = insn.word(2); 1647 v.type_id = insn.word(1); 1648 out[std::make_pair(set, binding)] = v; 1649 } 1650 } 1651} 1652 1653static bool validate_interface_between_stages(layer_data *my_data, VkDevice dev, shader_module const *producer, 1654 spirv_inst_iter producer_entrypoint, char const *producer_name, 1655 shader_module const *consumer, spirv_inst_iter consumer_entrypoint, 1656 char const *consumer_name, bool consumer_arrayed_input) { 1657 std::map<location_t, interface_var> outputs; 1658 std::map<location_t, interface_var> inputs; 1659 1660 bool pass = true; 1661 1662 collect_interface_by_location(my_data, dev, producer, producer_entrypoint, spv::StorageClassOutput, outputs, false); 1663 collect_interface_by_location(my_data, dev, consumer, consumer_entrypoint, spv::StorageClassInput, inputs, 1664 consumer_arrayed_input); 1665 1666 auto a_it = outputs.begin(); 1667 auto b_it = inputs.begin(); 1668 1669 /* maps sorted by key (location); walk them together to find mismatches */ 1670 while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) { 1671 bool a_at_end = outputs.size() == 0 || a_it == outputs.end(); 1672 bool b_at_end = inputs.size() == 0 || b_it == inputs.end(); 1673 auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first; 1674 auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first; 1675 1676 if (b_at_end || ((!a_at_end) && (a_first < b_first))) { 1677 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 1678 /*dev*/ 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", 1679 "%s writes to output location %u.%u which is not consumed by %s", producer_name, a_first.first, 1680 a_first.second, consumer_name)) { 1681 pass = false; 1682 } 1683 a_it++; 1684 } else if (a_at_end || a_first > b_first) { 1685 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1686 __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", 1687 "%s consumes input location %u.%u which is not written by %s", consumer_name, b_first.first, b_first.second, 1688 producer_name)) { 1689 pass = false; 1690 } 1691 b_it++; 1692 } else { 1693 if (types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id, consumer_arrayed_input)) { 1694 /* OK! */ 1695 } else { 1696 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1697 __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'", 1698 a_first.first, a_first.second, 1699 describe_type(producer, a_it->second.type_id).c_str(), 1700 describe_type(consumer, b_it->second.type_id).c_str())) { 1701 pass = false; 1702 } 1703 } 1704 a_it++; 1705 b_it++; 1706 } 1707 } 1708 1709 return pass; 1710} 1711 1712enum FORMAT_TYPE { 1713 FORMAT_TYPE_UNDEFINED, 1714 FORMAT_TYPE_FLOAT, /* UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader */ 1715 FORMAT_TYPE_SINT, 1716 FORMAT_TYPE_UINT, 1717}; 1718 1719static unsigned get_format_type(VkFormat fmt) { 1720 switch (fmt) { 1721 case VK_FORMAT_UNDEFINED: 1722 return FORMAT_TYPE_UNDEFINED; 1723 case VK_FORMAT_R8_SINT: 1724 case VK_FORMAT_R8G8_SINT: 1725 case VK_FORMAT_R8G8B8_SINT: 1726 case VK_FORMAT_R8G8B8A8_SINT: 1727 case VK_FORMAT_R16_SINT: 1728 case VK_FORMAT_R16G16_SINT: 1729 case VK_FORMAT_R16G16B16_SINT: 1730 case VK_FORMAT_R16G16B16A16_SINT: 1731 case VK_FORMAT_R32_SINT: 1732 case VK_FORMAT_R32G32_SINT: 1733 case VK_FORMAT_R32G32B32_SINT: 1734 case VK_FORMAT_R32G32B32A32_SINT: 1735 case VK_FORMAT_B8G8R8_SINT: 1736 case VK_FORMAT_B8G8R8A8_SINT: 1737 case VK_FORMAT_A2B10G10R10_SINT_PACK32: 1738 case VK_FORMAT_A2R10G10B10_SINT_PACK32: 1739 return FORMAT_TYPE_SINT; 1740 case VK_FORMAT_R8_UINT: 1741 case VK_FORMAT_R8G8_UINT: 1742 case VK_FORMAT_R8G8B8_UINT: 1743 case VK_FORMAT_R8G8B8A8_UINT: 1744 case VK_FORMAT_R16_UINT: 1745 case VK_FORMAT_R16G16_UINT: 1746 case VK_FORMAT_R16G16B16_UINT: 1747 case VK_FORMAT_R16G16B16A16_UINT: 1748 case VK_FORMAT_R32_UINT: 1749 case VK_FORMAT_R32G32_UINT: 1750 case VK_FORMAT_R32G32B32_UINT: 1751 case VK_FORMAT_R32G32B32A32_UINT: 1752 case VK_FORMAT_B8G8R8_UINT: 1753 case VK_FORMAT_B8G8R8A8_UINT: 1754 case VK_FORMAT_A2B10G10R10_UINT_PACK32: 1755 case VK_FORMAT_A2R10G10B10_UINT_PACK32: 1756 return FORMAT_TYPE_UINT; 1757 default: 1758 return FORMAT_TYPE_FLOAT; 1759 } 1760} 1761 1762/* characterizes a SPIR-V type appearing in an interface to a FF stage, 1763 * for comparison to a VkFormat's characterization above. */ 1764static unsigned get_fundamental_type(shader_module const *src, unsigned type) { 1765 auto insn = src->get_def(type); 1766 assert(insn != src->end()); 1767 1768 switch (insn.opcode()) { 1769 case spv::OpTypeInt: 1770 return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT; 1771 case spv::OpTypeFloat: 1772 return FORMAT_TYPE_FLOAT; 1773 case spv::OpTypeVector: 1774 return get_fundamental_type(src, insn.word(2)); 1775 case spv::OpTypeMatrix: 1776 return get_fundamental_type(src, insn.word(2)); 1777 case spv::OpTypeArray: 1778 return get_fundamental_type(src, insn.word(2)); 1779 case spv::OpTypePointer: 1780 return get_fundamental_type(src, insn.word(3)); 1781 default: 1782 return FORMAT_TYPE_UNDEFINED; 1783 } 1784} 1785 1786static uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) { 1787 uint32_t bit_pos = u_ffs(stage); 1788 return bit_pos - 1; 1789} 1790 1791static bool validate_vi_consistency(layer_data *my_data, VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi) { 1792 /* walk the binding descriptions, which describe the step rate and stride of each vertex buffer. 1793 * each binding should be specified only once. 1794 */ 1795 std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings; 1796 bool pass = true; 1797 1798 for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) { 1799 auto desc = &vi->pVertexBindingDescriptions[i]; 1800 auto &binding = bindings[desc->binding]; 1801 if (binding) { 1802 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1803 __LINE__, SHADER_CHECKER_INCONSISTENT_VI, "SC", 1804 "Duplicate vertex input binding descriptions for binding %d", desc->binding)) { 1805 pass = false; 1806 } 1807 } else { 1808 binding = desc; 1809 } 1810 } 1811 1812 return pass; 1813} 1814 1815static bool validate_vi_against_vs_inputs(layer_data *my_data, VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi, 1816 shader_module const *vs, spirv_inst_iter entrypoint) { 1817 std::map<location_t, interface_var> inputs; 1818 bool pass = true; 1819 1820 collect_interface_by_location(my_data, dev, vs, entrypoint, spv::StorageClassInput, inputs, false); 1821 1822 /* Build index by location */ 1823 std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs; 1824 if (vi) { 1825 for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) 1826 attribs[vi->pVertexAttributeDescriptions[i].location] = &vi->pVertexAttributeDescriptions[i]; 1827 } 1828 1829 auto it_a = attribs.begin(); 1830 auto it_b = inputs.begin(); 1831 1832 while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) { 1833 bool a_at_end = attribs.size() == 0 || it_a == attribs.end(); 1834 bool b_at_end = inputs.size() == 0 || it_b == inputs.end(); 1835 auto a_first = a_at_end ? 0 : it_a->first; 1836 auto b_first = b_at_end ? 0 : it_b->first.first; 1837 if (!a_at_end && (b_at_end || a_first < b_first)) { 1838 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 1839 /*dev*/ 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", 1840 "Vertex attribute at location %d not consumed by VS", a_first)) { 1841 pass = false; 1842 } 1843 it_a++; 1844 } else if (!b_at_end && (a_at_end || b_first < a_first)) { 1845 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1846 __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "VS consumes input at location %d but not provided", 1847 b_first)) { 1848 pass = false; 1849 } 1850 it_b++; 1851 } else { 1852 unsigned attrib_type = get_format_type(it_a->second->format); 1853 unsigned input_type = get_fundamental_type(vs, it_b->second.type_id); 1854 1855 /* type checking */ 1856 if (attrib_type != FORMAT_TYPE_UNDEFINED && input_type != FORMAT_TYPE_UNDEFINED && attrib_type != input_type) { 1857 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1858 __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", 1859 "Attribute type of `%s` at location %d does not match VS input type of `%s`", 1860 string_VkFormat(it_a->second->format), a_first, 1861 describe_type(vs, it_b->second.type_id).c_str())) { 1862 pass = false; 1863 } 1864 } 1865 1866 /* OK! */ 1867 it_a++; 1868 it_b++; 1869 } 1870 } 1871 1872 return pass; 1873} 1874 1875static bool validate_fs_outputs_against_render_pass(layer_data *my_data, VkDevice dev, shader_module const *fs, 1876 spirv_inst_iter entrypoint, RENDER_PASS_NODE const *rp, uint32_t subpass) { 1877 const std::vector<VkFormat> &color_formats = rp->subpassColorFormats[subpass]; 1878 std::map<location_t, interface_var> outputs; 1879 bool pass = true; 1880 1881 /* TODO: dual source blend index (spv::DecIndex, zero if not provided) */ 1882 1883 collect_interface_by_location(my_data, dev, fs, entrypoint, spv::StorageClassOutput, outputs, false); 1884 1885 auto it = outputs.begin(); 1886 uint32_t attachment = 0; 1887 1888 /* Walk attachment list and outputs together -- this is a little overpowered since attachments 1889 * are currently dense, but the parallel with matching between shader stages is nice. 1890 */ 1891 1892 while ((outputs.size() > 0 && it != outputs.end()) || attachment < color_formats.size()) { 1893 if (attachment == color_formats.size() || (it != outputs.end() && it->first.first < attachment)) { 1894 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1895 __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", 1896 "FS writes to output location %d with no matching attachment", it->first.first)) { 1897 pass = false; 1898 } 1899 it++; 1900 } else if (it == outputs.end() || it->first.first > attachment) { 1901 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1902 __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by FS", attachment)) { 1903 pass = false; 1904 } 1905 attachment++; 1906 } else { 1907 unsigned output_type = get_fundamental_type(fs, it->second.type_id); 1908 unsigned att_type = get_format_type(color_formats[attachment]); 1909 1910 /* type checking */ 1911 if (att_type != FORMAT_TYPE_UNDEFINED && output_type != FORMAT_TYPE_UNDEFINED && att_type != output_type) { 1912 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1913 __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", 1914 "Attachment %d of type `%s` does not match FS output type of `%s`", attachment, 1915 string_VkFormat(color_formats[attachment]), 1916 describe_type(fs, it->second.type_id).c_str())) { 1917 pass = false; 1918 } 1919 } 1920 1921 /* OK! */ 1922 it++; 1923 attachment++; 1924 } 1925 } 1926 1927 return pass; 1928} 1929 1930/* For some analyses, we need to know about all ids referenced by the static call tree of a particular 1931 * entrypoint. This is important for identifying the set of shader resources actually used by an entrypoint, 1932 * for example. 1933 * Note: we only explore parts of the image which might actually contain ids we care about for the above analyses. 1934 * - NOT the shader input/output interfaces. 1935 * 1936 * TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth 1937 * converting parts of this to be generated from the machine-readable spec instead. 1938 */ 1939static void mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint, std::unordered_set<uint32_t> &ids) { 1940 std::unordered_set<uint32_t> worklist; 1941 worklist.insert(entrypoint.word(2)); 1942 1943 while (!worklist.empty()) { 1944 auto id_iter = worklist.begin(); 1945 auto id = *id_iter; 1946 worklist.erase(id_iter); 1947 1948 auto insn = src->get_def(id); 1949 if (insn == src->end()) { 1950 /* id is something we didnt collect in build_def_index. that's OK -- we'll stumble 1951 * across all kinds of things here that we may not care about. */ 1952 continue; 1953 } 1954 1955 /* try to add to the output set */ 1956 if (!ids.insert(id).second) { 1957 continue; /* if we already saw this id, we don't want to walk it again. */ 1958 } 1959 1960 switch (insn.opcode()) { 1961 case spv::OpFunction: 1962 /* scan whole body of the function, enlisting anything interesting */ 1963 while (++insn, insn.opcode() != spv::OpFunctionEnd) { 1964 switch (insn.opcode()) { 1965 case spv::OpLoad: 1966 case spv::OpAtomicLoad: 1967 case spv::OpAtomicExchange: 1968 case spv::OpAtomicCompareExchange: 1969 case spv::OpAtomicCompareExchangeWeak: 1970 case spv::OpAtomicIIncrement: 1971 case spv::OpAtomicIDecrement: 1972 case spv::OpAtomicIAdd: 1973 case spv::OpAtomicISub: 1974 case spv::OpAtomicSMin: 1975 case spv::OpAtomicUMin: 1976 case spv::OpAtomicSMax: 1977 case spv::OpAtomicUMax: 1978 case spv::OpAtomicAnd: 1979 case spv::OpAtomicOr: 1980 case spv::OpAtomicXor: 1981 worklist.insert(insn.word(3)); /* ptr */ 1982 break; 1983 case spv::OpStore: 1984 case spv::OpAtomicStore: 1985 worklist.insert(insn.word(1)); /* ptr */ 1986 break; 1987 case spv::OpAccessChain: 1988 case spv::OpInBoundsAccessChain: 1989 worklist.insert(insn.word(3)); /* base ptr */ 1990 break; 1991 case spv::OpSampledImage: 1992 case spv::OpImageSampleImplicitLod: 1993 case spv::OpImageSampleExplicitLod: 1994 case spv::OpImageSampleDrefImplicitLod: 1995 case spv::OpImageSampleDrefExplicitLod: 1996 case spv::OpImageSampleProjImplicitLod: 1997 case spv::OpImageSampleProjExplicitLod: 1998 case spv::OpImageSampleProjDrefImplicitLod: 1999 case spv::OpImageSampleProjDrefExplicitLod: 2000 case spv::OpImageFetch: 2001 case spv::OpImageGather: 2002 case spv::OpImageDrefGather: 2003 case spv::OpImageRead: 2004 case spv::OpImage: 2005 case spv::OpImageQueryFormat: 2006 case spv::OpImageQueryOrder: 2007 case spv::OpImageQuerySizeLod: 2008 case spv::OpImageQuerySize: 2009 case spv::OpImageQueryLod: 2010 case spv::OpImageQueryLevels: 2011 case spv::OpImageQuerySamples: 2012 case spv::OpImageSparseSampleImplicitLod: 2013 case spv::OpImageSparseSampleExplicitLod: 2014 case spv::OpImageSparseSampleDrefImplicitLod: 2015 case spv::OpImageSparseSampleDrefExplicitLod: 2016 case spv::OpImageSparseSampleProjImplicitLod: 2017 case spv::OpImageSparseSampleProjExplicitLod: 2018 case spv::OpImageSparseSampleProjDrefImplicitLod: 2019 case spv::OpImageSparseSampleProjDrefExplicitLod: 2020 case spv::OpImageSparseFetch: 2021 case spv::OpImageSparseGather: 2022 case spv::OpImageSparseDrefGather: 2023 case spv::OpImageTexelPointer: 2024 worklist.insert(insn.word(3)); /* image or sampled image */ 2025 break; 2026 case spv::OpImageWrite: 2027 worklist.insert(insn.word(1)); /* image -- different operand order to above */ 2028 break; 2029 case spv::OpFunctionCall: 2030 for (auto i = 3; i < insn.len(); i++) { 2031 worklist.insert(insn.word(i)); /* fn itself, and all args */ 2032 } 2033 break; 2034 2035 case spv::OpExtInst: 2036 for (auto i = 5; i < insn.len(); i++) { 2037 worklist.insert(insn.word(i)); /* operands to ext inst */ 2038 } 2039 break; 2040 } 2041 } 2042 break; 2043 } 2044 } 2045} 2046 2047struct shader_stage_attributes { 2048 char const *const name; 2049 bool arrayed_input; 2050}; 2051 2052static shader_stage_attributes shader_stage_attribs[] = { 2053 {"vertex shader", false}, 2054 {"tessellation control shader", true}, 2055 {"tessellation evaluation shader", false}, 2056 {"geometry shader", true}, 2057 {"fragment shader", false}, 2058}; 2059 2060static bool validate_push_constant_block_against_pipeline(layer_data *my_data, VkDevice dev, 2061 std::vector<VkPushConstantRange> const *pushConstantRanges, 2062 shader_module const *src, spirv_inst_iter type, 2063 VkShaderStageFlagBits stage) { 2064 bool pass = true; 2065 2066 /* strip off ptrs etc */ 2067 type = get_struct_type(src, type, false); 2068 assert(type != src->end()); 2069 2070 /* validate directly off the offsets. this isn't quite correct for arrays 2071 * and matrices, but is a good first step. TODO: arrays, matrices, weird 2072 * sizes */ 2073 for (auto insn : *src) { 2074 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) { 2075 2076 if (insn.word(3) == spv::DecorationOffset) { 2077 unsigned offset = insn.word(4); 2078 auto size = 4; /* bytes; TODO: calculate this based on the type */ 2079 2080 bool found_range = false; 2081 for (auto const &range : *pushConstantRanges) { 2082 if (range.offset <= offset && range.offset + range.size >= offset + size) { 2083 found_range = true; 2084 2085 if ((range.stageFlags & stage) == 0) { 2086 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2087 /* dev */ 0, __LINE__, SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC", 2088 "Push constant range covering variable starting at " 2089 "offset %u not accessible from stage %s", 2090 offset, string_VkShaderStageFlagBits(stage))) { 2091 pass = false; 2092 } 2093 } 2094 2095 break; 2096 } 2097 } 2098 2099 if (!found_range) { 2100 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2101 /* dev */ 0, __LINE__, SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC", 2102 "Push constant range covering variable starting at " 2103 "offset %u not declared in layout", 2104 offset)) { 2105 pass = false; 2106 } 2107 } 2108 } 2109 } 2110 } 2111 2112 return pass; 2113} 2114 2115static bool validate_push_constant_usage(layer_data *my_data, VkDevice dev, 2116 std::vector<VkPushConstantRange> const *pushConstantRanges, shader_module const *src, 2117 std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) { 2118 bool pass = true; 2119 2120 for (auto id : accessible_ids) { 2121 auto def_insn = src->get_def(id); 2122 if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) { 2123 pass = validate_push_constant_block_against_pipeline(my_data, dev, pushConstantRanges, src, 2124 src->get_def(def_insn.word(1)), stage) && 2125 pass; 2126 } 2127 } 2128 2129 return pass; 2130} 2131 2132// For given pipelineLayout verify that the setLayout at slot.first 2133// has the requested binding at slot.second 2134static VkDescriptorSetLayoutBinding const * get_descriptor_binding(layer_data *my_data, vector<VkDescriptorSetLayout> *pipelineLayout, descriptor_slot_t slot) { 2135 2136 if (!pipelineLayout) 2137 return nullptr; 2138 2139 if (slot.first >= pipelineLayout->size()) 2140 return nullptr; 2141 2142 auto const layout_node = my_data->descriptorSetLayoutMap[(*pipelineLayout)[slot.first]]; 2143 2144 auto bindingIt = layout_node->bindingToIndexMap.find(slot.second); 2145 if ((bindingIt == layout_node->bindingToIndexMap.end()) || (layout_node->createInfo.pBindings == NULL)) 2146 return nullptr; 2147 2148 assert(bindingIt->second < layout_node->createInfo.bindingCount); 2149 return &layout_node->createInfo.pBindings[bindingIt->second]; 2150} 2151 2152// Block of code at start here for managing/tracking Pipeline state that this layer cares about 2153 2154static uint64_t g_drawCount[NUM_DRAW_TYPES] = {0, 0, 0, 0}; 2155 2156// TODO : Should be tracking lastBound per commandBuffer and when draws occur, report based on that cmd buffer lastBound 2157// Then need to synchronize the accesses based on cmd buffer so that if I'm reading state on one cmd buffer, updates 2158// to that same cmd buffer by separate thread are not changing state from underneath us 2159// Track the last cmd buffer touched by this thread 2160 2161static VkBool32 hasDrawCmd(GLOBAL_CB_NODE *pCB) { 2162 for (uint32_t i = 0; i < NUM_DRAW_TYPES; i++) { 2163 if (pCB->drawCount[i]) 2164 return VK_TRUE; 2165 } 2166 return VK_FALSE; 2167} 2168 2169// Check object status for selected flag state 2170static VkBool32 validate_status(layer_data *my_data, GLOBAL_CB_NODE *pNode, CBStatusFlags enable_mask, CBStatusFlags status_mask, 2171 CBStatusFlags status_flag, VkFlags msg_flags, DRAW_STATE_ERROR error_code, const char *fail_msg) { 2172 // If non-zero enable mask is present, check it against status but if enable_mask 2173 // is 0 then no enable required so we should always just check status 2174 if ((!enable_mask) || (enable_mask & pNode->status)) { 2175 if ((pNode->status & status_mask) != status_flag) { 2176 // TODO : How to pass dispatchable objects as srcObject? Here src obj should be cmd buffer 2177 return log_msg(my_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, error_code, 2178 "DS", "CB object %#" PRIxLEAST64 ": %s", (uint64_t)(pNode->commandBuffer), fail_msg); 2179 } 2180 } 2181 return VK_FALSE; 2182} 2183 2184// Retrieve pipeline node ptr for given pipeline object 2185static PIPELINE_NODE *getPipeline(layer_data *my_data, const VkPipeline pipeline) { 2186 if (my_data->pipelineMap.find(pipeline) == my_data->pipelineMap.end()) { 2187 return NULL; 2188 } 2189 return my_data->pipelineMap[pipeline]; 2190} 2191 2192// Return VK_TRUE if for a given PSO, the given state enum is dynamic, else return VK_FALSE 2193static VkBool32 isDynamic(const PIPELINE_NODE *pPipeline, const VkDynamicState state) { 2194 if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) { 2195 for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) { 2196 if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) 2197 return VK_TRUE; 2198 } 2199 } 2200 return VK_FALSE; 2201} 2202 2203// Validate state stored as flags at time of draw call 2204static VkBool32 validate_draw_state_flags(layer_data *my_data, GLOBAL_CB_NODE *pCB, VkBool32 indexedDraw) { 2205 VkBool32 result; 2206 result = 2207 validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_VIEWPORT_SET, CBSTATUS_VIEWPORT_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2208 DRAWSTATE_VIEWPORT_NOT_BOUND, "Dynamic viewport state not set for this command buffer"); 2209 result |= 2210 validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_SCISSOR_SET, CBSTATUS_SCISSOR_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2211 DRAWSTATE_SCISSOR_NOT_BOUND, "Dynamic scissor state not set for this command buffer"); 2212 result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_LINE_WIDTH_SET, CBSTATUS_LINE_WIDTH_SET, 2213 VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_LINE_WIDTH_NOT_BOUND, 2214 "Dynamic line width state not set for this command buffer"); 2215 result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_DEPTH_BIAS_SET, CBSTATUS_DEPTH_BIAS_SET, 2216 VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_DEPTH_BIAS_NOT_BOUND, 2217 "Dynamic depth bias state not set for this command buffer"); 2218 result |= validate_status(my_data, pCB, CBSTATUS_COLOR_BLEND_WRITE_ENABLE, CBSTATUS_BLEND_SET, CBSTATUS_BLEND_SET, 2219 VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_BLEND_NOT_BOUND, 2220 "Dynamic blend object state not set for this command buffer"); 2221 result |= validate_status(my_data, pCB, CBSTATUS_DEPTH_WRITE_ENABLE, CBSTATUS_DEPTH_BOUNDS_SET, CBSTATUS_DEPTH_BOUNDS_SET, 2222 VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_DEPTH_BOUNDS_NOT_BOUND, 2223 "Dynamic depth bounds state not set for this command buffer"); 2224 result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_READ_MASK_SET, 2225 CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND, 2226 "Dynamic stencil read mask state not set for this command buffer"); 2227 result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_WRITE_MASK_SET, 2228 CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND, 2229 "Dynamic stencil write mask state not set for this command buffer"); 2230 result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_REFERENCE_SET, 2231 CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND, 2232 "Dynamic stencil reference state not set for this command buffer"); 2233 if (indexedDraw) 2234 result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_INDEX_BUFFER_BOUND, CBSTATUS_INDEX_BUFFER_BOUND, 2235 VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_INDEX_BUFFER_NOT_BOUND, 2236 "Index buffer object not bound to this command buffer when Indexed Draw attempted"); 2237 return result; 2238} 2239 2240// Verify attachment reference compatibility according to spec 2241// If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this 2242// If both AttachmentReference arrays have requested index, check their corresponding AttachementDescriptions 2243// to make sure that format and samples counts match. 2244// If not, they are not compatible. 2245static bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary, 2246 const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments, 2247 const VkAttachmentReference *pSecondary, const uint32_t secondaryCount, 2248 const VkAttachmentDescription *pSecondaryAttachments) { 2249 if (index >= primaryCount) { // Check secondary as if primary is VK_ATTACHMENT_UNUSED 2250 if (VK_ATTACHMENT_UNUSED != pSecondary[index].attachment) 2251 return false; 2252 } else if (index >= secondaryCount) { // Check primary as if secondary is VK_ATTACHMENT_UNUSED 2253 if (VK_ATTACHMENT_UNUSED != pPrimary[index].attachment) 2254 return false; 2255 } else { // format and sample count must match 2256 if ((pPrimaryAttachments[pPrimary[index].attachment].format == 2257 pSecondaryAttachments[pSecondary[index].attachment].format) && 2258 (pPrimaryAttachments[pPrimary[index].attachment].samples == 2259 pSecondaryAttachments[pSecondary[index].attachment].samples)) 2260 return true; 2261 } 2262 // Format and sample counts didn't match 2263 return false; 2264} 2265 2266// For give primary and secondary RenderPass objects, verify that they're compatible 2267static bool verify_renderpass_compatibility(layer_data *my_data, const VkRenderPass primaryRP, const VkRenderPass secondaryRP, 2268 string &errorMsg) { 2269 stringstream errorStr; 2270 if (my_data->renderPassMap.find(primaryRP) == my_data->renderPassMap.end()) { 2271 errorStr << "invalid VkRenderPass (" << primaryRP << ")"; 2272 errorMsg = errorStr.str(); 2273 return false; 2274 } else if (my_data->renderPassMap.find(secondaryRP) == my_data->renderPassMap.end()) { 2275 errorStr << "invalid VkRenderPass (" << secondaryRP << ")"; 2276 errorMsg = errorStr.str(); 2277 return false; 2278 } 2279 // Trivial pass case is exact same RP 2280 if (primaryRP == secondaryRP) { 2281 return true; 2282 } 2283 const VkRenderPassCreateInfo *primaryRPCI = my_data->renderPassMap[primaryRP]->pCreateInfo; 2284 const VkRenderPassCreateInfo *secondaryRPCI = my_data->renderPassMap[secondaryRP]->pCreateInfo; 2285 if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) { 2286 errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount 2287 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses."; 2288 errorMsg = errorStr.str(); 2289 return false; 2290 } 2291 uint32_t spIndex = 0; 2292 for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) { 2293 // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible 2294 uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount; 2295 uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount; 2296 uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount); 2297 for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) { 2298 if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount, 2299 primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments, 2300 secondaryColorCount, secondaryRPCI->pAttachments)) { 2301 errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible."; 2302 errorMsg = errorStr.str(); 2303 return false; 2304 } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments, 2305 primaryColorCount, primaryRPCI->pAttachments, 2306 secondaryRPCI->pSubpasses[spIndex].pResolveAttachments, 2307 secondaryColorCount, secondaryRPCI->pAttachments)) { 2308 errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible."; 2309 errorMsg = errorStr.str(); 2310 return false; 2311 } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 2312 primaryColorCount, primaryRPCI->pAttachments, 2313 secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 2314 secondaryColorCount, secondaryRPCI->pAttachments)) { 2315 errorStr << "depth/stencil attachments at index " << cIdx << " of subpass index " << spIndex 2316 << " are not compatible."; 2317 errorMsg = errorStr.str(); 2318 return false; 2319 } 2320 } 2321 uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount; 2322 uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount; 2323 uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount); 2324 for (uint32_t i = 0; i < inputMax; ++i) { 2325 if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryColorCount, 2326 primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments, 2327 secondaryColorCount, secondaryRPCI->pAttachments)) { 2328 errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible."; 2329 errorMsg = errorStr.str(); 2330 return false; 2331 } 2332 } 2333 } 2334 return true; 2335} 2336 2337// For give SET_NODE, verify that its Set is compatible w/ the setLayout corresponding to pipelineLayout[layoutIndex] 2338static bool verify_set_layout_compatibility(layer_data *my_data, const SET_NODE *pSet, const VkPipelineLayout layout, 2339 const uint32_t layoutIndex, string &errorMsg) { 2340 stringstream errorStr; 2341 auto pipeline_layout_it = my_data->pipelineLayoutMap.find(layout); 2342 if (pipeline_layout_it == my_data->pipelineLayoutMap.end()) { 2343 errorStr << "invalid VkPipelineLayout (" << layout << ")"; 2344 errorMsg = errorStr.str(); 2345 return false; 2346 } 2347 if (layoutIndex >= pipeline_layout_it->second.descriptorSetLayouts.size()) { 2348 errorStr << "VkPipelineLayout (" << layout << ") only contains " << pipeline_layout_it->second.descriptorSetLayouts.size() 2349 << " setLayouts corresponding to sets 0-" << pipeline_layout_it->second.descriptorSetLayouts.size() - 1 2350 << ", but you're attempting to bind set to index " << layoutIndex; 2351 errorMsg = errorStr.str(); 2352 return false; 2353 } 2354 // Get the specific setLayout from PipelineLayout that overlaps this set 2355 LAYOUT_NODE *pLayoutNode = my_data->descriptorSetLayoutMap[pipeline_layout_it->second.descriptorSetLayouts[layoutIndex]]; 2356 if (pLayoutNode->layout == pSet->pLayout->layout) { // trivial pass case 2357 return true; 2358 } 2359 size_t descriptorCount = pLayoutNode->descriptorTypes.size(); 2360 if (descriptorCount != pSet->pLayout->descriptorTypes.size()) { 2361 errorStr << "setLayout " << layoutIndex << " from pipelineLayout " << layout << " has " << descriptorCount 2362 << " descriptors, but corresponding set being bound has " << pSet->pLayout->descriptorTypes.size() 2363 << " descriptors."; 2364 errorMsg = errorStr.str(); 2365 return false; // trivial fail case 2366 } 2367 // Now need to check set against corresponding pipelineLayout to verify compatibility 2368 for (size_t i = 0; i < descriptorCount; ++i) { 2369 // Need to verify that layouts are identically defined 2370 // TODO : Is below sufficient? Making sure that types & stageFlags match per descriptor 2371 // do we also need to check immutable samplers? 2372 if (pLayoutNode->descriptorTypes[i] != pSet->pLayout->descriptorTypes[i]) { 2373 errorStr << "descriptor " << i << " for descriptorSet being bound is type '" 2374 << string_VkDescriptorType(pSet->pLayout->descriptorTypes[i]) 2375 << "' but corresponding descriptor from pipelineLayout is type '" 2376 << string_VkDescriptorType(pLayoutNode->descriptorTypes[i]) << "'"; 2377 errorMsg = errorStr.str(); 2378 return false; 2379 } 2380 if (pLayoutNode->stageFlags[i] != pSet->pLayout->stageFlags[i]) { 2381 errorStr << "stageFlags " << i << " for descriptorSet being bound is " << pSet->pLayout->stageFlags[i] 2382 << "' but corresponding descriptor from pipelineLayout has stageFlags " << pLayoutNode->stageFlags[i]; 2383 errorMsg = errorStr.str(); 2384 return false; 2385 } 2386 } 2387 return true; 2388} 2389 2390// Validate that data for each specialization entry is fully contained within the buffer. 2391static VkBool32 validate_specialization_offsets(layer_data *my_data, VkPipelineShaderStageCreateInfo const *info) { 2392 VkBool32 pass = VK_TRUE; 2393 2394 VkSpecializationInfo const *spec = info->pSpecializationInfo; 2395 2396 if (spec) { 2397 for (auto i = 0u; i < spec->mapEntryCount; i++) { 2398 if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) { 2399 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2400 /*dev*/ 0, __LINE__, SHADER_CHECKER_BAD_SPECIALIZATION, "SC", 2401 "Specialization entry %u (for constant id %u) references memory outside provided " 2402 "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER 2403 " bytes provided)", 2404 i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset, 2405 spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize)) { 2406 2407 pass = VK_FALSE; 2408 } 2409 } 2410 } 2411 } 2412 2413 return pass; 2414} 2415 2416static bool descriptor_type_match(layer_data *my_data, shader_module const *module, uint32_t type_id, 2417 VkDescriptorType descriptor_type, unsigned &descriptor_count) { 2418 auto type = module->get_def(type_id); 2419 2420 descriptor_count = 1; 2421 2422 /* Strip off any array or ptrs. Where we remove array levels, adjust the 2423 * descriptor count for each dimension. */ 2424 while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) { 2425 if (type.opcode() == spv::OpTypeArray) { 2426 descriptor_count *= get_constant_value(module, type.word(3)); 2427 type = module->get_def(type.word(2)); 2428 } 2429 else { 2430 type = module->get_def(type.word(3)); 2431 } 2432 } 2433 2434 switch (type.opcode()) { 2435 case spv::OpTypeStruct: { 2436 for (auto insn : *module) { 2437 if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) { 2438 if (insn.word(2) == spv::DecorationBlock) { 2439 return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || 2440 descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 2441 } else if (insn.word(2) == spv::DecorationBufferBlock) { 2442 return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || 2443 descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; 2444 } 2445 } 2446 } 2447 2448 /* Invalid */ 2449 return false; 2450 } 2451 2452 case spv::OpTypeSampler: 2453 return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER; 2454 2455 case spv::OpTypeSampledImage: 2456 return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 2457 2458 case spv::OpTypeImage: { 2459 /* Many descriptor types backing image types-- depends on dimension 2460 * and whether the image will be used with a sampler. SPIRV for 2461 * Vulkan requires that sampled be 1 or 2 -- leaving the decision to 2462 * runtime is unacceptable. 2463 */ 2464 auto dim = type.word(3); 2465 auto sampled = type.word(7); 2466 2467 if (dim == spv::DimSubpassData) { 2468 return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; 2469 } else if (dim == spv::DimBuffer) { 2470 if (sampled == 1) { 2471 return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; 2472 } else { 2473 return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; 2474 } 2475 } else if (sampled == 1) { 2476 return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; 2477 } else { 2478 return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; 2479 } 2480 } 2481 2482 /* We shouldn't really see any other junk types -- but if we do, they're 2483 * a mismatch. 2484 */ 2485 default: 2486 return false; /* Mismatch */ 2487 } 2488} 2489 2490static VkBool32 require_feature(layer_data *my_data, VkBool32 feature, char const *feature_name) { 2491 if (!feature) { 2492 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2493 /* dev */ 0, __LINE__, SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC", 2494 "Shader requires VkPhysicalDeviceFeatures::%s but is not " 2495 "enabled on the device", 2496 feature_name)) { 2497 return false; 2498 } 2499 } 2500 2501 return true; 2502} 2503 2504static VkBool32 validate_shader_capabilities(layer_data *my_data, VkDevice dev, shader_module const *src) 2505{ 2506 VkBool32 pass = VK_TRUE; 2507 2508 auto enabledFeatures = &my_data->physDevProperties.features; 2509 2510 for (auto insn : *src) { 2511 if (insn.opcode() == spv::OpCapability) { 2512 switch (insn.word(1)) { 2513 case spv::CapabilityMatrix: 2514 case spv::CapabilityShader: 2515 case spv::CapabilityInputAttachment: 2516 case spv::CapabilitySampled1D: 2517 case spv::CapabilityImage1D: 2518 case spv::CapabilitySampledBuffer: 2519 case spv::CapabilityImageBuffer: 2520 case spv::CapabilityImageQuery: 2521 case spv::CapabilityDerivativeControl: 2522 // Always supported by a Vulkan 1.0 implementation -- no feature bits. 2523 break; 2524 2525 case spv::CapabilityGeometry: 2526 pass &= require_feature(my_data, enabledFeatures->geometryShader, "geometryShader"); 2527 break; 2528 2529 case spv::CapabilityTessellation: 2530 pass &= require_feature(my_data, enabledFeatures->tessellationShader, "tessellationShader"); 2531 break; 2532 2533 case spv::CapabilityFloat64: 2534 pass &= require_feature(my_data, enabledFeatures->shaderFloat64, "shaderFloat64"); 2535 break; 2536 2537 case spv::CapabilityInt64: 2538 pass &= require_feature(my_data, enabledFeatures->shaderInt64, "shaderInt64"); 2539 break; 2540 2541 case spv::CapabilityTessellationPointSize: 2542 case spv::CapabilityGeometryPointSize: 2543 pass &= require_feature(my_data, enabledFeatures->shaderTessellationAndGeometryPointSize, 2544 "shaderTessellationAndGeometryPointSize"); 2545 break; 2546 2547 case spv::CapabilityImageGatherExtended: 2548 pass &= require_feature(my_data, enabledFeatures->shaderImageGatherExtended, "shaderImageGatherExtended"); 2549 break; 2550 2551 case spv::CapabilityStorageImageMultisample: 2552 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageMultisample, "shaderStorageImageMultisample"); 2553 break; 2554 2555 case spv::CapabilityUniformBufferArrayDynamicIndexing: 2556 pass &= require_feature(my_data, enabledFeatures->shaderUniformBufferArrayDynamicIndexing, 2557 "shaderUniformBufferArrayDynamicIndexing"); 2558 break; 2559 2560 case spv::CapabilitySampledImageArrayDynamicIndexing: 2561 pass &= require_feature(my_data, enabledFeatures->shaderSampledImageArrayDynamicIndexing, 2562 "shaderSampledImageArrayDynamicIndexing"); 2563 break; 2564 2565 case spv::CapabilityStorageBufferArrayDynamicIndexing: 2566 pass &= require_feature(my_data, enabledFeatures->shaderStorageBufferArrayDynamicIndexing, 2567 "shaderStorageBufferArrayDynamicIndexing"); 2568 break; 2569 2570 case spv::CapabilityStorageImageArrayDynamicIndexing: 2571 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageArrayDynamicIndexing, 2572 "shaderStorageImageArrayDynamicIndexing"); 2573 break; 2574 2575 case spv::CapabilityClipDistance: 2576 pass &= require_feature(my_data, enabledFeatures->shaderClipDistance, "shaderClipDistance"); 2577 break; 2578 2579 case spv::CapabilityCullDistance: 2580 pass &= require_feature(my_data, enabledFeatures->shaderCullDistance, "shaderCullDistance"); 2581 break; 2582 2583 case spv::CapabilityImageCubeArray: 2584 pass &= require_feature(my_data, enabledFeatures->imageCubeArray, "imageCubeArray"); 2585 break; 2586 2587 case spv::CapabilitySampleRateShading: 2588 pass &= require_feature(my_data, enabledFeatures->sampleRateShading, "sampleRateShading"); 2589 break; 2590 2591 case spv::CapabilitySparseResidency: 2592 pass &= require_feature(my_data, enabledFeatures->shaderResourceResidency, "shaderResourceResidency"); 2593 break; 2594 2595 case spv::CapabilityMinLod: 2596 pass &= require_feature(my_data, enabledFeatures->shaderResourceMinLod, "shaderResourceMinLod"); 2597 break; 2598 2599 case spv::CapabilitySampledCubeArray: 2600 pass &= require_feature(my_data, enabledFeatures->imageCubeArray, "imageCubeArray"); 2601 break; 2602 2603 case spv::CapabilityImageMSArray: 2604 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageMultisample, "shaderStorageImageMultisample"); 2605 break; 2606 2607 case spv::CapabilityStorageImageExtendedFormats: 2608 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageExtendedFormats, 2609 "shaderStorageImageExtendedFormats"); 2610 break; 2611 2612 case spv::CapabilityInterpolationFunction: 2613 pass &= require_feature(my_data, enabledFeatures->sampleRateShading, "sampleRateShading"); 2614 break; 2615 2616 case spv::CapabilityStorageImageReadWithoutFormat: 2617 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageReadWithoutFormat, 2618 "shaderStorageImageReadWithoutFormat"); 2619 break; 2620 2621 case spv::CapabilityStorageImageWriteWithoutFormat: 2622 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageWriteWithoutFormat, 2623 "shaderStorageImageWriteWithoutFormat"); 2624 break; 2625 2626 case spv::CapabilityMultiViewport: 2627 pass &= require_feature(my_data, enabledFeatures->multiViewport, "multiViewport"); 2628 break; 2629 2630 default: 2631 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /* dev */0, 2632 __LINE__, SHADER_CHECKER_BAD_CAPABILITY, "SC", 2633 "Shader declares capability %u, not supported in Vulkan.", 2634 insn.word(1))) 2635 pass = VK_FALSE; 2636 break; 2637 } 2638 } 2639 } 2640 2641 return pass; 2642} 2643 2644 2645// Validate that the shaders used by the given pipeline 2646// As a side effect this function also records the sets that are actually used by the pipeline 2647static VkBool32 validate_pipeline_shaders(layer_data *my_data, VkDevice dev, PIPELINE_NODE *pPipeline) { 2648 VkGraphicsPipelineCreateInfo const *pCreateInfo = &pPipeline->graphicsPipelineCI; 2649 /* We seem to allow pipeline stages to be specified out of order, so collect and identify them 2650 * before trying to do anything more: */ 2651 int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT); 2652 int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT); 2653 2654 shader_module *shaders[5]; 2655 memset(shaders, 0, sizeof(shaders)); 2656 spirv_inst_iter entrypoints[5]; 2657 memset(entrypoints, 0, sizeof(entrypoints)); 2658 RENDER_PASS_NODE const *rp = 0; 2659 VkPipelineVertexInputStateCreateInfo const *vi = 0; 2660 VkBool32 pass = VK_TRUE; 2661 2662 for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { 2663 VkPipelineShaderStageCreateInfo const *pStage = &pCreateInfo->pStages[i]; 2664 if (pStage->sType == VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO) { 2665 2666 if ((pStage->stage & (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | 2667 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) == 0) { 2668 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2669 /*dev*/ 0, __LINE__, SHADER_CHECKER_UNKNOWN_STAGE, "SC", "Unknown shader stage %d", pStage->stage)) { 2670 pass = VK_FALSE; 2671 } 2672 } else { 2673 pass = validate_specialization_offsets(my_data, pStage) && pass; 2674 2675 auto stage_id = get_shader_stage_id(pStage->stage); 2676 auto module = my_data->shaderModuleMap[pStage->module].get(); 2677 shaders[stage_id] = module; 2678 2679 /* find the entrypoint */ 2680 entrypoints[stage_id] = find_entrypoint(module, pStage->pName, pStage->stage); 2681 if (entrypoints[stage_id] == module->end()) { 2682 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2683 /*dev*/ 0, __LINE__, SHADER_CHECKER_MISSING_ENTRYPOINT, "SC", 2684 "No entrypoint found named `%s` for stage %s", pStage->pName, 2685 string_VkShaderStageFlagBits(pStage->stage))) { 2686 pass = VK_FALSE; 2687 } 2688 } 2689 2690 /* validate shader capabilities against enabled device features */ 2691 pass = validate_shader_capabilities(my_data, dev, module) && pass; 2692 2693 /* mark accessible ids */ 2694 std::unordered_set<uint32_t> accessible_ids; 2695 mark_accessible_ids(module, entrypoints[stage_id], accessible_ids); 2696 2697 /* validate descriptor set layout against what the entrypoint actually uses */ 2698 std::map<descriptor_slot_t, interface_var> descriptor_uses; 2699 collect_interface_by_descriptor_slot(my_data, dev, module, accessible_ids, descriptor_uses); 2700 2701 auto layouts = pCreateInfo->layout != VK_NULL_HANDLE 2702 ? &(my_data->pipelineLayoutMap[pCreateInfo->layout].descriptorSetLayouts) 2703 : nullptr; 2704 2705 for (auto use : descriptor_uses) { 2706 // As a side-effect of this function, capture which sets are used by the pipeline 2707 pPipeline->active_sets.insert(use.first.first); 2708 2709 /* find the matching binding */ 2710 auto binding = get_descriptor_binding(my_data, layouts, use.first); 2711 unsigned required_descriptor_count; 2712 2713 if (!binding) { 2714 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2715 /*dev*/ 0, __LINE__, SHADER_CHECKER_MISSING_DESCRIPTOR, "SC", 2716 "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout", 2717 use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str())) { 2718 pass = VK_FALSE; 2719 } 2720 } else if (~binding->stageFlags & pStage->stage) { 2721 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2722 /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC", 2723 "Shader uses descriptor slot %u.%u (used " 2724 "as type `%s`) but descriptor not " 2725 "accessible from stage %s", 2726 use.first.first, use.first.second, 2727 describe_type(module, use.second.type_id).c_str(), 2728 string_VkShaderStageFlagBits(pStage->stage))) { 2729 pass = VK_FALSE; 2730 } 2731 } else if (!descriptor_type_match(my_data, module, use.second.type_id, binding->descriptorType, /*out*/ required_descriptor_count)) { 2732 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2733 /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC", 2734 "Type mismatch on descriptor slot " 2735 "%u.%u (used as type `%s`) but " 2736 "descriptor of type %s", 2737 use.first.first, use.first.second, 2738 describe_type(module, use.second.type_id).c_str(), 2739 string_VkDescriptorType(binding->descriptorType))) { 2740 pass = VK_FALSE; 2741 } 2742 } else if (binding->descriptorCount < required_descriptor_count) { 2743 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2744 /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC", 2745 "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided", 2746 required_descriptor_count, use.first.first, use.first.second, 2747 describe_type(module, use.second.type_id).c_str(), 2748 binding->descriptorCount)) { 2749 pass = VK_FALSE; 2750 } 2751 } 2752 } 2753 2754 /* validate push constant usage */ 2755 pass = 2756 validate_push_constant_usage(my_data, dev, &my_data->pipelineLayoutMap[pCreateInfo->layout].pushConstantRanges, 2757 module, accessible_ids, pStage->stage) && 2758 pass; 2759 } 2760 } 2761 } 2762 2763 if (pCreateInfo->renderPass != VK_NULL_HANDLE) 2764 rp = my_data->renderPassMap[pCreateInfo->renderPass]; 2765 2766 vi = pCreateInfo->pVertexInputState; 2767 2768 if (vi) { 2769 pass = validate_vi_consistency(my_data, dev, vi) && pass; 2770 } 2771 2772 if (shaders[vertex_stage]) { 2773 pass = validate_vi_against_vs_inputs(my_data, dev, vi, shaders[vertex_stage], entrypoints[vertex_stage]) && pass; 2774 } 2775 2776 /* TODO: enforce rules about present combinations of shaders */ 2777 int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT); 2778 int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); 2779 2780 while (!shaders[producer] && producer != fragment_stage) { 2781 producer++; 2782 consumer++; 2783 } 2784 2785 for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) { 2786 assert(shaders[producer]); 2787 if (shaders[consumer]) { 2788 pass = validate_interface_between_stages(my_data, dev, shaders[producer], entrypoints[producer], 2789 shader_stage_attribs[producer].name, shaders[consumer], entrypoints[consumer], 2790 shader_stage_attribs[consumer].name, 2791 shader_stage_attribs[consumer].arrayed_input) && 2792 pass; 2793 2794 producer = consumer; 2795 } 2796 } 2797 2798 if (shaders[fragment_stage] && rp) { 2799 pass = validate_fs_outputs_against_render_pass(my_data, dev, shaders[fragment_stage], entrypoints[fragment_stage], rp, 2800 pCreateInfo->subpass) && 2801 pass; 2802 } 2803 2804 return pass; 2805} 2806 2807// Return Set node ptr for specified set or else NULL 2808static SET_NODE *getSetNode(layer_data *my_data, const VkDescriptorSet set) { 2809 if (my_data->setMap.find(set) == my_data->setMap.end()) { 2810 return NULL; 2811 } 2812 return my_data->setMap[set]; 2813} 2814// For the given command buffer, verify that for each set set in activeSetNodes 2815// that any dynamic descriptor in that set has a valid dynamic offset bound. 2816// To be valid, the dynamic offset combined with the offset and range from its 2817// descriptor update must not overflow the size of its buffer being updated 2818static VkBool32 validate_dynamic_offsets(layer_data *my_data, const GLOBAL_CB_NODE *pCB, const vector<SET_NODE *> activeSetNodes) { 2819 VkBool32 result = VK_FALSE; 2820 2821 VkWriteDescriptorSet *pWDS = NULL; 2822 uint32_t dynOffsetIndex = 0; 2823 VkDeviceSize bufferSize = 0; 2824 for (auto set_node : activeSetNodes) { 2825 for (uint32_t i = 0; i < set_node->descriptorCount; ++i) { 2826 // TODO: Add validation for descriptors dynamically skipped in shader 2827 if (set_node->ppDescriptors[i] != NULL) { 2828 switch (set_node->ppDescriptors[i]->sType) { 2829 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 2830 pWDS = (VkWriteDescriptorSet *)set_node->ppDescriptors[i]; 2831 if ((pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) || 2832 (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) { 2833 for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) { 2834 bufferSize = my_data->bufferMap[pWDS->pBufferInfo[j].buffer].create_info->size; 2835 uint32_t dynOffset = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].dynamicOffsets[dynOffsetIndex]; 2836 if (pWDS->pBufferInfo[j].range == VK_WHOLE_SIZE) { 2837 if ((dynOffset + pWDS->pBufferInfo[j].offset) > bufferSize) { 2838 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2839 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 2840 reinterpret_cast<const uint64_t &>(set_node->set), __LINE__, 2841 DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS", 2842 "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has range of " 2843 "VK_WHOLE_SIZE but dynamic offset %#" PRIxLEAST32 ". " 2844 "combined with offset %#" PRIxLEAST64 " oversteps its buffer (%#" PRIxLEAST64 2845 ") which has a size of %#" PRIxLEAST64 ".", 2846 reinterpret_cast<const uint64_t &>(set_node->set), i, 2847 pCB->dynamicOffsets[dynOffsetIndex], pWDS->pBufferInfo[j].offset, 2848 reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize); 2849 } 2850 } else if ((dynOffset + pWDS->pBufferInfo[j].offset + pWDS->pBufferInfo[j].range) > bufferSize) { 2851 result |= log_msg( 2852 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2853 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 2854 reinterpret_cast<const uint64_t &>(set_node->set), __LINE__, DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, 2855 "DS", 2856 "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has dynamic offset %#" PRIxLEAST32 ". " 2857 "Combined with offset %#" PRIxLEAST64 " and range %#" PRIxLEAST64 2858 " from its update, this oversteps its buffer " 2859 "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".", 2860 reinterpret_cast<const uint64_t &>(set_node->set), i, pCB->dynamicOffsets[dynOffsetIndex], 2861 pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range, 2862 reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize); 2863 } else if ((dynOffset + pWDS->pBufferInfo[j].offset + pWDS->pBufferInfo[j].range) > bufferSize) { 2864 result |= log_msg( 2865 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2866 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 2867 reinterpret_cast<const uint64_t &>(set_node->set), __LINE__, DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, 2868 "DS", 2869 "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has dynamic offset %#" PRIxLEAST32 ". " 2870 "Combined with offset %#" PRIxLEAST64 " and range %#" PRIxLEAST64 2871 " from its update, this oversteps its buffer " 2872 "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".", 2873 reinterpret_cast<const uint64_t &>(set_node->set), i, pCB->dynamicOffsets[dynOffsetIndex], 2874 pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range, 2875 reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize); 2876 } 2877 dynOffsetIndex++; 2878 i += j; // Advance i to end of this set of descriptors (++i at end of for loop will move 1 index past 2879 // last of these descriptors) 2880 } 2881 } 2882 break; 2883 default: // Currently only shadowing Write update nodes so shouldn't get here 2884 assert(0); 2885 continue; 2886 } 2887 } 2888 } 2889 } 2890 return result; 2891} 2892 2893// Validate overall state at the time of a draw call 2894static VkBool32 validate_draw_state(layer_data *my_data, GLOBAL_CB_NODE *pCB, VkBool32 indexedDraw) { 2895 // First check flag states 2896 VkBool32 result = validate_draw_state_flags(my_data, pCB, indexedDraw); 2897 PIPELINE_NODE *pPipe = getPipeline(my_data, pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline); 2898 // Now complete other state checks 2899 // TODO : Currently only performing next check if *something* was bound (non-zero last bound) 2900 // There is probably a better way to gate when this check happens, and to know if something *should* have been bound 2901 // We should have that check separately and then gate this check based on that check 2902 if (pPipe) { 2903 auto const &state = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS]; 2904 if (state.pipelineLayout) { 2905 string errorString; 2906 // Need a vector (vs. std::set) of active Sets for dynamicOffset validation in case same set bound w/ different offsets 2907 vector<SET_NODE *> activeSetNodes; 2908 for (auto setIndex : pPipe->active_sets) { 2909 // If valid set is not bound throw an error 2910 if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) { 2911 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 2912 __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS", 2913 "VkPipeline %#" PRIxLEAST64 " uses set #%u but that set is not bound.", 2914 (uint64_t)pPipe->pipeline, setIndex); 2915 } else if (!verify_set_layout_compatibility(my_data, my_data->setMap[state.boundDescriptorSets[setIndex]], 2916 pPipe->graphicsPipelineCI.layout, setIndex, errorString)) { 2917 // Set is bound but not compatible w/ overlapping pipelineLayout from PSO 2918 VkDescriptorSet setHandle = my_data->setMap[state.boundDescriptorSets[setIndex]]->set; 2919 result |= log_msg( 2920 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 2921 (uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS", 2922 "VkDescriptorSet (%#" PRIxLEAST64 2923 ") bound as set #%u is not compatible with overlapping VkPipelineLayout %#" PRIxLEAST64 " due to: %s", 2924 (uint64_t)setHandle, setIndex, (uint64_t)pPipe->graphicsPipelineCI.layout, errorString.c_str()); 2925 } else { // Valid set is bound and layout compatible, validate that it's updated and verify any dynamic offsets 2926 // Pull the set node 2927 SET_NODE *pSet = my_data->setMap[state.boundDescriptorSets[setIndex]]; 2928 // Save vector of all active sets to verify dynamicOffsets below 2929 activeSetNodes.push_back(pSet); 2930 // Make sure set has been updated 2931 if (!pSet->pUpdateStructs) { 2932 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2933 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pSet->set, __LINE__, 2934 DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS", 2935 "DS %#" PRIxLEAST64 " bound but it was never updated. It is now being used to draw so " 2936 "this will result in undefined behavior.", 2937 (uint64_t)pSet->set); 2938 } 2939 } 2940 } 2941 // For each dynamic descriptor, make sure dynamic offset doesn't overstep buffer 2942 if (!state.dynamicOffsets.empty()) 2943 result |= validate_dynamic_offsets(my_data, pCB, activeSetNodes); 2944 } 2945 // Verify Vtx binding 2946 if (pPipe->vertexBindingDescriptions.size() > 0) { 2947 for (size_t i = 0; i < pPipe->vertexBindingDescriptions.size(); i++) { 2948 if ((pCB->currentDrawData.buffers.size() < (i + 1)) || (pCB->currentDrawData.buffers[i] == VK_NULL_HANDLE)) { 2949 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 2950 __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS", 2951 "The Pipeline State Object (%#" PRIxLEAST64 2952 ") expects that this Command Buffer's vertex binding Index " PRINTF_SIZE_T_SPECIFIER 2953 " should be set via vkCmdBindVertexBuffers.", 2954 (uint64_t)pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline, i); 2955 } 2956 } 2957 } else { 2958 if (!pCB->currentDrawData.buffers.empty()) { 2959 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 2960 0, __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS", 2961 "Vertex buffers are bound to command buffer (%#" PRIxLEAST64 2962 ") but no vertex buffers are attached to this Pipeline State Object (%#" PRIxLEAST64 ").", 2963 (uint64_t)pCB->commandBuffer, (uint64_t)pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline); 2964 } 2965 } 2966 // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count. 2967 // Skip check if rasterization is disabled or there is no viewport. 2968 if ((!pPipe->graphicsPipelineCI.pRasterizationState || 2969 !pPipe->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) && 2970 pPipe->graphicsPipelineCI.pViewportState) { 2971 VkBool32 dynViewport = isDynamic(pPipe, VK_DYNAMIC_STATE_VIEWPORT); 2972 VkBool32 dynScissor = isDynamic(pPipe, VK_DYNAMIC_STATE_SCISSOR); 2973 if (dynViewport) { 2974 if (pCB->viewports.size() != pPipe->graphicsPipelineCI.pViewportState->viewportCount) { 2975 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 2976 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", 2977 "Dynamic viewportCount from vkCmdSetViewport() is " PRINTF_SIZE_T_SPECIFIER 2978 ", but PSO viewportCount is %u. These counts must match.", 2979 pCB->viewports.size(), pPipe->graphicsPipelineCI.pViewportState->viewportCount); 2980 } 2981 } 2982 if (dynScissor) { 2983 if (pCB->scissors.size() != pPipe->graphicsPipelineCI.pViewportState->scissorCount) { 2984 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 2985 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", 2986 "Dynamic scissorCount from vkCmdSetScissor() is " PRINTF_SIZE_T_SPECIFIER 2987 ", but PSO scissorCount is %u. These counts must match.", 2988 pCB->scissors.size(), pPipe->graphicsPipelineCI.pViewportState->scissorCount); 2989 } 2990 } 2991 } 2992 } 2993 return result; 2994} 2995 2996// Verify that create state for a pipeline is valid 2997static VkBool32 verifyPipelineCreateState(layer_data *my_data, const VkDevice device, std::vector<PIPELINE_NODE *> pPipelines, 2998 int pipelineIndex) { 2999 VkBool32 skipCall = VK_FALSE; 3000 3001 PIPELINE_NODE *pPipeline = pPipelines[pipelineIndex]; 3002 3003 // If create derivative bit is set, check that we've specified a base 3004 // pipeline correctly, and that the base pipeline was created to allow 3005 // derivatives. 3006 if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) { 3007 PIPELINE_NODE *pBasePipeline = nullptr; 3008 if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^ 3009 (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) { 3010 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3011 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", 3012 "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified"); 3013 } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) { 3014 if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) { 3015 skipCall |= 3016 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3017 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", 3018 "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline."); 3019 } else { 3020 pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex]; 3021 } 3022 } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) { 3023 pBasePipeline = getPipeline(my_data, pPipeline->graphicsPipelineCI.basePipelineHandle); 3024 } 3025 3026 if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) { 3027 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3028 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", 3029 "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives."); 3030 } 3031 } 3032 3033 if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) { 3034 if (!my_data->physDevProperties.features.independentBlend) { 3035 if (pPipeline->attachments.size() > 0) { 3036 VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0]; 3037 for (size_t i = 1; i < pPipeline->attachments.size(); i++) { 3038 if ((pAttachments[0].blendEnable != pAttachments[i].blendEnable) || 3039 (pAttachments[0].srcColorBlendFactor != pAttachments[i].srcColorBlendFactor) || 3040 (pAttachments[0].dstColorBlendFactor != pAttachments[i].dstColorBlendFactor) || 3041 (pAttachments[0].colorBlendOp != pAttachments[i].colorBlendOp) || 3042 (pAttachments[0].srcAlphaBlendFactor != pAttachments[i].srcAlphaBlendFactor) || 3043 (pAttachments[0].dstAlphaBlendFactor != pAttachments[i].dstAlphaBlendFactor) || 3044 (pAttachments[0].alphaBlendOp != pAttachments[i].alphaBlendOp) || 3045 (pAttachments[0].colorWriteMask != pAttachments[i].colorWriteMask)) { 3046 skipCall |= 3047 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3048 DRAWSTATE_INDEPENDENT_BLEND, "DS", "Invalid Pipeline CreateInfo: If independent blend feature not " 3049 "enabled, all elements of pAttachments must be identical"); 3050 } 3051 } 3052 } 3053 } 3054 if (!my_data->physDevProperties.features.logicOp && 3055 (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) { 3056 skipCall |= 3057 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3058 DRAWSTATE_DISABLED_LOGIC_OP, "DS", 3059 "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE"); 3060 } 3061 if ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable == VK_TRUE) && 3062 ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOp < VK_LOGIC_OP_CLEAR) || 3063 (pPipeline->graphicsPipelineCI.pColorBlendState->logicOp > VK_LOGIC_OP_SET))) { 3064 skipCall |= 3065 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3066 DRAWSTATE_INVALID_LOGIC_OP, "DS", 3067 "Invalid Pipeline CreateInfo: If logicOpEnable is VK_TRUE, logicOp must be a valid VkLogicOp value"); 3068 } 3069 } 3070 3071 // Ensure the subpass index is valid. If not, then validate_pipeline_shaders 3072 // produces nonsense errors that confuse users. Other layers should already 3073 // emit errors for renderpass being invalid. 3074 auto rp_data = my_data->renderPassMap.find(pPipeline->graphicsPipelineCI.renderPass); 3075 if (rp_data != my_data->renderPassMap.end() && 3076 pPipeline->graphicsPipelineCI.subpass >= rp_data->second->pCreateInfo->subpassCount) { 3077 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3078 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Subpass index %u " 3079 "is out of range for this renderpass (0..%u)", 3080 pPipeline->graphicsPipelineCI.subpass, rp_data->second->pCreateInfo->subpassCount - 1); 3081 } 3082 3083 if (!validate_pipeline_shaders(my_data, device, pPipeline)) { 3084 skipCall = VK_TRUE; 3085 } 3086 // VS is required 3087 if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) { 3088 skipCall |= 3089 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3090 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Vtx Shader required"); 3091 } 3092 // Either both or neither TC/TE shaders should be defined 3093 if (((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) == 0) != 3094 ((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) == 0)) { 3095 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3096 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", 3097 "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair"); 3098 } 3099 // Compute shaders should be specified independent of Gfx shaders 3100 if ((pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) && 3101 (pPipeline->active_shaders & 3102 (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | 3103 VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT))) { 3104 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3105 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", 3106 "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline"); 3107 } 3108 // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines. 3109 // Mismatching primitive topology and tessellation fails graphics pipeline creation. 3110 if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) && 3111 (pPipeline->iaStateCI.topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) { 3112 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3113 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: " 3114 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA " 3115 "topology for tessellation pipelines"); 3116 } 3117 if (pPipeline->iaStateCI.topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) { 3118 if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) { 3119 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3120 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: " 3121 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive " 3122 "topology is only valid for tessellation pipelines"); 3123 } 3124 if (!pPipeline->tessStateCI.patchControlPoints || (pPipeline->tessStateCI.patchControlPoints > 32)) { 3125 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3126 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: " 3127 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive " 3128 "topology used with patchControlPoints value %u." 3129 " patchControlPoints should be >0 and <=32.", 3130 pPipeline->tessStateCI.patchControlPoints); 3131 } 3132 } 3133 // Viewport state must be included if rasterization is enabled. 3134 // If the viewport state is included, the viewport and scissor counts should always match. 3135 // NOTE : Even if these are flagged as dynamic, counts need to be set correctly for shader compiler 3136 if (!pPipeline->graphicsPipelineCI.pRasterizationState || 3137 !pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) { 3138 if (!pPipeline->graphicsPipelineCI.pViewportState) { 3139 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3140 DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "Gfx Pipeline pViewportState is null. Even if viewport " 3141 "and scissors are dynamic PSO must include " 3142 "viewportCount and scissorCount in pViewportState."); 3143 } else if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount != 3144 pPipeline->graphicsPipelineCI.pViewportState->viewportCount) { 3145 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3146 DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", 3147 "Gfx Pipeline viewport count (%u) must match scissor count (%u).", 3148 pPipeline->vpStateCI.viewportCount, pPipeline->vpStateCI.scissorCount); 3149 } else { 3150 // If viewport or scissor are not dynamic, then verify that data is appropriate for count 3151 VkBool32 dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT); 3152 VkBool32 dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR); 3153 if (!dynViewport) { 3154 if (pPipeline->graphicsPipelineCI.pViewportState->viewportCount && 3155 !pPipeline->graphicsPipelineCI.pViewportState->pViewports) { 3156 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 3157 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", 3158 "Gfx Pipeline viewportCount is %u, but pViewports is NULL. For non-zero viewportCount, you " 3159 "must either include pViewports data, or include viewport in pDynamicState and set it with " 3160 "vkCmdSetViewport().", 3161 pPipeline->graphicsPipelineCI.pViewportState->viewportCount); 3162 } 3163 } 3164 if (!dynScissor) { 3165 if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount && 3166 !pPipeline->graphicsPipelineCI.pViewportState->pScissors) { 3167 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 3168 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", 3169 "Gfx Pipeline scissorCount is %u, but pScissors is NULL. For non-zero scissorCount, you " 3170 "must either include pScissors data, or include scissor in pDynamicState and set it with " 3171 "vkCmdSetScissor().", 3172 pPipeline->graphicsPipelineCI.pViewportState->scissorCount); 3173 } 3174 } 3175 } 3176 } 3177 return skipCall; 3178} 3179 3180// Init the pipeline mapping info based on pipeline create info LL tree 3181// Threading note : Calls to this function should wrapped in mutex 3182// TODO : this should really just be in the constructor for PIPELINE_NODE 3183static PIPELINE_NODE *initGraphicsPipeline(layer_data *dev_data, const VkGraphicsPipelineCreateInfo *pCreateInfo) { 3184 PIPELINE_NODE *pPipeline = new PIPELINE_NODE; 3185 3186 // First init create info 3187 memcpy(&pPipeline->graphicsPipelineCI, pCreateInfo, sizeof(VkGraphicsPipelineCreateInfo)); 3188 3189 size_t bufferSize = 0; 3190 const VkPipelineVertexInputStateCreateInfo *pVICI = NULL; 3191 const VkPipelineColorBlendStateCreateInfo *pCBCI = NULL; 3192 3193 for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { 3194 const VkPipelineShaderStageCreateInfo *pPSSCI = &pCreateInfo->pStages[i]; 3195 3196 switch (pPSSCI->stage) { 3197 case VK_SHADER_STAGE_VERTEX_BIT: 3198 memcpy(&pPipeline->vsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); 3199 pPipeline->active_shaders |= VK_SHADER_STAGE_VERTEX_BIT; 3200 break; 3201 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: 3202 memcpy(&pPipeline->tcsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); 3203 pPipeline->active_shaders |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; 3204 break; 3205 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: 3206 memcpy(&pPipeline->tesCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); 3207 pPipeline->active_shaders |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; 3208 break; 3209 case VK_SHADER_STAGE_GEOMETRY_BIT: 3210 memcpy(&pPipeline->gsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); 3211 pPipeline->active_shaders |= VK_SHADER_STAGE_GEOMETRY_BIT; 3212 break; 3213 case VK_SHADER_STAGE_FRAGMENT_BIT: 3214 memcpy(&pPipeline->fsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); 3215 pPipeline->active_shaders |= VK_SHADER_STAGE_FRAGMENT_BIT; 3216 break; 3217 case VK_SHADER_STAGE_COMPUTE_BIT: 3218 // TODO : Flag error, CS is specified through VkComputePipelineCreateInfo 3219 pPipeline->active_shaders |= VK_SHADER_STAGE_COMPUTE_BIT; 3220 break; 3221 default: 3222 // TODO : Flag error 3223 break; 3224 } 3225 } 3226 // Copy over GraphicsPipelineCreateInfo structure embedded pointers 3227 if (pCreateInfo->stageCount != 0) { 3228 pPipeline->graphicsPipelineCI.pStages = new VkPipelineShaderStageCreateInfo[pCreateInfo->stageCount]; 3229 bufferSize = pCreateInfo->stageCount * sizeof(VkPipelineShaderStageCreateInfo); 3230 memcpy((void *)pPipeline->graphicsPipelineCI.pStages, pCreateInfo->pStages, bufferSize); 3231 } 3232 if (pCreateInfo->pVertexInputState != NULL) { 3233 pPipeline->vertexInputCI = *pCreateInfo->pVertexInputState; 3234 // Copy embedded ptrs 3235 pVICI = pCreateInfo->pVertexInputState; 3236 if (pVICI->vertexBindingDescriptionCount) { 3237 pPipeline->vertexBindingDescriptions = std::vector<VkVertexInputBindingDescription>( 3238 pVICI->pVertexBindingDescriptions, pVICI->pVertexBindingDescriptions + pVICI->vertexBindingDescriptionCount); 3239 } 3240 if (pVICI->vertexAttributeDescriptionCount) { 3241 pPipeline->vertexAttributeDescriptions = std::vector<VkVertexInputAttributeDescription>( 3242 pVICI->pVertexAttributeDescriptions, pVICI->pVertexAttributeDescriptions + pVICI->vertexAttributeDescriptionCount); 3243 } 3244 pPipeline->graphicsPipelineCI.pVertexInputState = &pPipeline->vertexInputCI; 3245 } 3246 if (pCreateInfo->pInputAssemblyState != NULL) { 3247 pPipeline->iaStateCI = *pCreateInfo->pInputAssemblyState; 3248 pPipeline->graphicsPipelineCI.pInputAssemblyState = &pPipeline->iaStateCI; 3249 } 3250 if (pCreateInfo->pTessellationState != NULL) { 3251 pPipeline->tessStateCI = *pCreateInfo->pTessellationState; 3252 pPipeline->graphicsPipelineCI.pTessellationState = &pPipeline->tessStateCI; 3253 } 3254 if (pCreateInfo->pViewportState != NULL) { 3255 pPipeline->vpStateCI = *pCreateInfo->pViewportState; 3256 pPipeline->graphicsPipelineCI.pViewportState = &pPipeline->vpStateCI; 3257 } 3258 if (pCreateInfo->pRasterizationState != NULL) { 3259 pPipeline->rsStateCI = *pCreateInfo->pRasterizationState; 3260 pPipeline->graphicsPipelineCI.pRasterizationState = &pPipeline->rsStateCI; 3261 } 3262 if (pCreateInfo->pMultisampleState != NULL) { 3263 pPipeline->msStateCI = *pCreateInfo->pMultisampleState; 3264 pPipeline->graphicsPipelineCI.pMultisampleState = &pPipeline->msStateCI; 3265 } 3266 if (pCreateInfo->pDepthStencilState != NULL) { 3267 pPipeline->dsStateCI = *pCreateInfo->pDepthStencilState; 3268 pPipeline->graphicsPipelineCI.pDepthStencilState = &pPipeline->dsStateCI; 3269 } 3270 if (pCreateInfo->pColorBlendState != NULL) { 3271 pPipeline->cbStateCI = *pCreateInfo->pColorBlendState; 3272 // Copy embedded ptrs 3273 pCBCI = pCreateInfo->pColorBlendState; 3274 if (pCBCI->attachmentCount) { 3275 pPipeline->attachments = std::vector<VkPipelineColorBlendAttachmentState>( 3276 pCBCI->pAttachments, pCBCI->pAttachments + pCBCI->attachmentCount); 3277 } 3278 pPipeline->graphicsPipelineCI.pColorBlendState = &pPipeline->cbStateCI; 3279 } 3280 if (pCreateInfo->pDynamicState != NULL) { 3281 pPipeline->dynStateCI = *pCreateInfo->pDynamicState; 3282 if (pPipeline->dynStateCI.dynamicStateCount) { 3283 pPipeline->dynStateCI.pDynamicStates = new VkDynamicState[pPipeline->dynStateCI.dynamicStateCount]; 3284 bufferSize = pPipeline->dynStateCI.dynamicStateCount * sizeof(VkDynamicState); 3285 memcpy((void *)pPipeline->dynStateCI.pDynamicStates, pCreateInfo->pDynamicState->pDynamicStates, bufferSize); 3286 } 3287 pPipeline->graphicsPipelineCI.pDynamicState = &pPipeline->dynStateCI; 3288 } 3289 return pPipeline; 3290} 3291 3292// Free the Pipeline nodes 3293static void deletePipelines(layer_data *my_data) { 3294 if (my_data->pipelineMap.size() <= 0) 3295 return; 3296 for (auto ii = my_data->pipelineMap.begin(); ii != my_data->pipelineMap.end(); ++ii) { 3297 if ((*ii).second->graphicsPipelineCI.stageCount != 0) { 3298 delete[](*ii).second->graphicsPipelineCI.pStages; 3299 } 3300 if ((*ii).second->dynStateCI.dynamicStateCount != 0) { 3301 delete[](*ii).second->dynStateCI.pDynamicStates; 3302 } 3303 delete (*ii).second; 3304 } 3305 my_data->pipelineMap.clear(); 3306} 3307 3308// For given pipeline, return number of MSAA samples, or one if MSAA disabled 3309static VkSampleCountFlagBits getNumSamples(layer_data *my_data, const VkPipeline pipeline) { 3310 PIPELINE_NODE *pPipe = my_data->pipelineMap[pipeline]; 3311 if (VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pPipe->msStateCI.sType) { 3312 return pPipe->msStateCI.rasterizationSamples; 3313 } 3314 return VK_SAMPLE_COUNT_1_BIT; 3315} 3316 3317// Validate state related to the PSO 3318static VkBool32 validatePipelineState(layer_data *my_data, const GLOBAL_CB_NODE *pCB, const VkPipelineBindPoint pipelineBindPoint, 3319 const VkPipeline pipeline) { 3320 if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) { 3321 // Verify that any MSAA request in PSO matches sample# in bound FB 3322 // Skip the check if rasterization is disabled. 3323 PIPELINE_NODE *pPipeline = my_data->pipelineMap[pipeline]; 3324 if (!pPipeline->graphicsPipelineCI.pRasterizationState || 3325 !pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) { 3326 VkSampleCountFlagBits psoNumSamples = getNumSamples(my_data, pipeline); 3327 if (pCB->activeRenderPass) { 3328 const VkRenderPassCreateInfo *pRPCI = my_data->renderPassMap[pCB->activeRenderPass]->pCreateInfo; 3329 const VkSubpassDescription *pSD = &pRPCI->pSubpasses[pCB->activeSubpass]; 3330 VkSampleCountFlagBits subpassNumSamples = (VkSampleCountFlagBits)0; 3331 uint32_t i; 3332 3333 for (i = 0; i < pSD->colorAttachmentCount; i++) { 3334 VkSampleCountFlagBits samples; 3335 3336 if (pSD->pColorAttachments[i].attachment == VK_ATTACHMENT_UNUSED) 3337 continue; 3338 3339 samples = pRPCI->pAttachments[pSD->pColorAttachments[i].attachment].samples; 3340 if (subpassNumSamples == (VkSampleCountFlagBits)0) { 3341 subpassNumSamples = samples; 3342 } else if (subpassNumSamples != samples) { 3343 subpassNumSamples = (VkSampleCountFlagBits)-1; 3344 break; 3345 } 3346 } 3347 if (pSD->pDepthStencilAttachment && pSD->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { 3348 const VkSampleCountFlagBits samples = pRPCI->pAttachments[pSD->pDepthStencilAttachment->attachment].samples; 3349 if (subpassNumSamples == (VkSampleCountFlagBits)0) 3350 subpassNumSamples = samples; 3351 else if (subpassNumSamples != samples) 3352 subpassNumSamples = (VkSampleCountFlagBits)-1; 3353 } 3354 3355 if (psoNumSamples != subpassNumSamples) { 3356 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, 3357 (uint64_t)pipeline, __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS", 3358 "Num samples mismatch! Binding PSO (%#" PRIxLEAST64 3359 ") with %u samples while current RenderPass (%#" PRIxLEAST64 ") w/ %u samples!", 3360 (uint64_t)pipeline, psoNumSamples, (uint64_t)pCB->activeRenderPass, subpassNumSamples); 3361 } 3362 } else { 3363 // TODO : I believe it's an error if we reach this point and don't have an activeRenderPass 3364 // Verify and flag error as appropriate 3365 } 3366 } 3367 // TODO : Add more checks here 3368 } else { 3369 // TODO : Validate non-gfx pipeline updates 3370 } 3371 return VK_FALSE; 3372} 3373 3374// Block of code at start here specifically for managing/tracking DSs 3375 3376// Return Pool node ptr for specified pool or else NULL 3377static DESCRIPTOR_POOL_NODE *getPoolNode(layer_data *my_data, const VkDescriptorPool pool) { 3378 if (my_data->descriptorPoolMap.find(pool) == my_data->descriptorPoolMap.end()) { 3379 return NULL; 3380 } 3381 return my_data->descriptorPoolMap[pool]; 3382} 3383 3384static LAYOUT_NODE *getLayoutNode(layer_data *my_data, const VkDescriptorSetLayout layout) { 3385 if (my_data->descriptorSetLayoutMap.find(layout) == my_data->descriptorSetLayoutMap.end()) { 3386 return NULL; 3387 } 3388 return my_data->descriptorSetLayoutMap[layout]; 3389} 3390 3391// Return VK_FALSE if update struct is of valid type, otherwise flag error and return code from callback 3392static VkBool32 validUpdateStruct(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) { 3393 switch (pUpdateStruct->sType) { 3394 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 3395 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: 3396 return VK_FALSE; 3397 default: 3398 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3399 DRAWSTATE_INVALID_UPDATE_STRUCT, "DS", 3400 "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", 3401 string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType); 3402 } 3403} 3404 3405// Set count for given update struct in the last parameter 3406// Return value of skipCall, which is only VK_TRUE if error occurs and callback signals execution to cease 3407static uint32_t getUpdateCount(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) { 3408 switch (pUpdateStruct->sType) { 3409 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 3410 return ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorCount; 3411 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: 3412 // TODO : Need to understand this case better and make sure code is correct 3413 return ((VkCopyDescriptorSet *)pUpdateStruct)->descriptorCount; 3414 default: 3415 return 0; 3416 } 3417 return 0; 3418} 3419 3420// For given Layout Node and binding, return index where that binding begins 3421static uint32_t getBindingStartIndex(const LAYOUT_NODE *pLayout, const uint32_t binding) { 3422 uint32_t offsetIndex = 0; 3423 for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) { 3424 if (pLayout->createInfo.pBindings[i].binding == binding) 3425 break; 3426 offsetIndex += pLayout->createInfo.pBindings[i].descriptorCount; 3427 } 3428 return offsetIndex; 3429} 3430 3431// For given layout node and binding, return last index that is updated 3432static uint32_t getBindingEndIndex(const LAYOUT_NODE *pLayout, const uint32_t binding) { 3433 uint32_t offsetIndex = 0; 3434 for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) { 3435 offsetIndex += pLayout->createInfo.pBindings[i].descriptorCount; 3436 if (pLayout->createInfo.pBindings[i].binding == binding) 3437 break; 3438 } 3439 return offsetIndex - 1; 3440} 3441 3442// For given layout and update, return the first overall index of the layout that is updated 3443static uint32_t getUpdateStartIndex(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, const uint32_t binding, 3444 const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) { 3445 return getBindingStartIndex(pLayout, binding) + arrayIndex; 3446} 3447 3448// For given layout and update, return the last overall index of the layout that is updated 3449static uint32_t getUpdateEndIndex(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, const uint32_t binding, 3450 const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) { 3451 uint32_t count = getUpdateCount(my_data, device, pUpdateStruct); 3452 return getBindingStartIndex(pLayout, binding) + arrayIndex + count - 1; 3453} 3454 3455// Verify that the descriptor type in the update struct matches what's expected by the layout 3456static VkBool32 validateUpdateConsistency(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, 3457 const GENERIC_HEADER *pUpdateStruct, uint32_t startIndex, uint32_t endIndex) { 3458 // First get actual type of update 3459 VkBool32 skipCall = VK_FALSE; 3460 VkDescriptorType actualType; 3461 uint32_t i = 0; 3462 switch (pUpdateStruct->sType) { 3463 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 3464 actualType = ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorType; 3465 break; 3466 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: 3467 /* no need to validate */ 3468 return VK_FALSE; 3469 break; 3470 default: 3471 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3472 DRAWSTATE_INVALID_UPDATE_STRUCT, "DS", 3473 "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", 3474 string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType); 3475 } 3476 if (VK_FALSE == skipCall) { 3477 // Set first stageFlags as reference and verify that all other updates match it 3478 VkShaderStageFlags refStageFlags = pLayout->stageFlags[startIndex]; 3479 for (i = startIndex; i <= endIndex; i++) { 3480 if (pLayout->descriptorTypes[i] != actualType) { 3481 skipCall |= log_msg( 3482 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3483 DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS", 3484 "Write descriptor update has descriptor type %s that does not match overlapping binding descriptor type of %s!", 3485 string_VkDescriptorType(actualType), string_VkDescriptorType(pLayout->descriptorTypes[i])); 3486 } 3487 if (pLayout->stageFlags[i] != refStageFlags) { 3488 skipCall |= log_msg( 3489 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3490 DRAWSTATE_DESCRIPTOR_STAGEFLAGS_MISMATCH, "DS", 3491 "Write descriptor update has stageFlags %x that do not match overlapping binding descriptor stageFlags of %x!", 3492 refStageFlags, pLayout->stageFlags[i]); 3493 } 3494 } 3495 } 3496 return skipCall; 3497} 3498 3499// Determine the update type, allocate a new struct of that type, shadow the given pUpdate 3500// struct into the pNewNode param. Return VK_TRUE if error condition encountered and callback signals early exit. 3501// NOTE : Calls to this function should be wrapped in mutex 3502static VkBool32 shadowUpdateNode(layer_data *my_data, const VkDevice device, GENERIC_HEADER *pUpdate, GENERIC_HEADER **pNewNode) { 3503 VkBool32 skipCall = VK_FALSE; 3504 VkWriteDescriptorSet *pWDS = NULL; 3505 VkCopyDescriptorSet *pCDS = NULL; 3506 switch (pUpdate->sType) { 3507 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 3508 pWDS = new VkWriteDescriptorSet; 3509 *pNewNode = (GENERIC_HEADER *)pWDS; 3510 memcpy(pWDS, pUpdate, sizeof(VkWriteDescriptorSet)); 3511 3512 switch (pWDS->descriptorType) { 3513 case VK_DESCRIPTOR_TYPE_SAMPLER: 3514 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: 3515 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: 3516 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { 3517 VkDescriptorImageInfo *info = new VkDescriptorImageInfo[pWDS->descriptorCount]; 3518 memcpy(info, pWDS->pImageInfo, pWDS->descriptorCount * sizeof(VkDescriptorImageInfo)); 3519 pWDS->pImageInfo = info; 3520 } break; 3521 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: 3522 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { 3523 VkBufferView *info = new VkBufferView[pWDS->descriptorCount]; 3524 memcpy(info, pWDS->pTexelBufferView, pWDS->descriptorCount * sizeof(VkBufferView)); 3525 pWDS->pTexelBufferView = info; 3526 } break; 3527 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: 3528 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: 3529 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: 3530 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { 3531 VkDescriptorBufferInfo *info = new VkDescriptorBufferInfo[pWDS->descriptorCount]; 3532 memcpy(info, pWDS->pBufferInfo, pWDS->descriptorCount * sizeof(VkDescriptorBufferInfo)); 3533 pWDS->pBufferInfo = info; 3534 } break; 3535 default: 3536 return VK_ERROR_VALIDATION_FAILED_EXT; 3537 break; 3538 } 3539 break; 3540 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: 3541 pCDS = new VkCopyDescriptorSet; 3542 *pNewNode = (GENERIC_HEADER *)pCDS; 3543 memcpy(pCDS, pUpdate, sizeof(VkCopyDescriptorSet)); 3544 break; 3545 default: 3546 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3547 DRAWSTATE_INVALID_UPDATE_STRUCT, "DS", 3548 "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", 3549 string_VkStructureType(pUpdate->sType), pUpdate->sType)) 3550 return VK_TRUE; 3551 } 3552 // Make sure that pNext for the end of shadow copy is NULL 3553 (*pNewNode)->pNext = NULL; 3554 return skipCall; 3555} 3556 3557// Verify that given sampler is valid 3558static VkBool32 validateSampler(const layer_data *my_data, const VkSampler *pSampler, const VkBool32 immutable) { 3559 VkBool32 skipCall = VK_FALSE; 3560 auto sampIt = my_data->sampleMap.find(*pSampler); 3561 if (sampIt == my_data->sampleMap.end()) { 3562 if (!immutable) { 3563 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, 3564 (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS", 3565 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid sampler %#" PRIxLEAST64, 3566 (uint64_t)*pSampler); 3567 } else { // immutable 3568 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, 3569 (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS", 3570 "vkUpdateDescriptorSets: Attempt to update descriptor whose binding has an invalid immutable " 3571 "sampler %#" PRIxLEAST64, 3572 (uint64_t)*pSampler); 3573 } 3574 } else { 3575 // TODO : Any further checks we want to do on the sampler? 3576 } 3577 return skipCall; 3578} 3579 3580// find layout(s) on the cmd buf level 3581bool FindLayout(const GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, IMAGE_CMD_BUF_LAYOUT_NODE &node) { 3582 ImageSubresourcePair imgpair = {image, true, range}; 3583 auto imgsubIt = pCB->imageLayoutMap.find(imgpair); 3584 if (imgsubIt == pCB->imageLayoutMap.end()) { 3585 imgpair = {image, false, VkImageSubresource()}; 3586 imgsubIt = pCB->imageLayoutMap.find(imgpair); 3587 if (imgsubIt == pCB->imageLayoutMap.end()) 3588 return false; 3589 } 3590 node = imgsubIt->second; 3591 return true; 3592} 3593 3594// find layout(s) on the global level 3595bool FindLayout(const layer_data *my_data, ImageSubresourcePair imgpair, VkImageLayout &layout) { 3596 auto imgsubIt = my_data->imageLayoutMap.find(imgpair); 3597 if (imgsubIt == my_data->imageLayoutMap.end()) { 3598 imgpair = {imgpair.image, false, VkImageSubresource()}; 3599 imgsubIt = my_data->imageLayoutMap.find(imgpair); 3600 if (imgsubIt == my_data->imageLayoutMap.end()) 3601 return false; 3602 } 3603 layout = imgsubIt->second.layout; 3604 return true; 3605} 3606 3607bool FindLayout(const layer_data *my_data, VkImage image, VkImageSubresource range, VkImageLayout &layout) { 3608 ImageSubresourcePair imgpair = {image, true, range}; 3609 return FindLayout(my_data, imgpair, layout); 3610} 3611 3612bool FindLayouts(const layer_data *my_data, VkImage image, std::vector<VkImageLayout> &layouts) { 3613 auto sub_data = my_data->imageSubresourceMap.find(image); 3614 if (sub_data == my_data->imageSubresourceMap.end()) 3615 return false; 3616 auto imgIt = my_data->imageMap.find(image); 3617 if (imgIt == my_data->imageMap.end()) 3618 return false; 3619 bool ignoreGlobal = false; 3620 // TODO: Make this robust for >1 aspect mask. Now it will just say ignore 3621 // potential errors in this case. 3622 if (sub_data->second.size() >= (imgIt->second.createInfo.arrayLayers * imgIt->second.createInfo.mipLevels + 1)) { 3623 ignoreGlobal = true; 3624 } 3625 for (auto imgsubpair : sub_data->second) { 3626 if (ignoreGlobal && !imgsubpair.hasSubresource) 3627 continue; 3628 auto img_data = my_data->imageLayoutMap.find(imgsubpair); 3629 if (img_data != my_data->imageLayoutMap.end()) { 3630 layouts.push_back(img_data->second.layout); 3631 } 3632 } 3633 return true; 3634} 3635 3636// Set the layout on the global level 3637void SetLayout(layer_data *my_data, ImageSubresourcePair imgpair, const VkImageLayout &layout) { 3638 VkImage &image = imgpair.image; 3639 // TODO (mlentine): Maybe set format if new? Not used atm. 3640 my_data->imageLayoutMap[imgpair].layout = layout; 3641 // TODO (mlentine): Maybe make vector a set? 3642 auto subresource = std::find(my_data->imageSubresourceMap[image].begin(), my_data->imageSubresourceMap[image].end(), imgpair); 3643 if (subresource == my_data->imageSubresourceMap[image].end()) { 3644 my_data->imageSubresourceMap[image].push_back(imgpair); 3645 } 3646} 3647 3648void SetLayout(layer_data *my_data, VkImage image, const VkImageLayout &layout) { 3649 ImageSubresourcePair imgpair = {image, false, VkImageSubresource()}; 3650 SetLayout(my_data, imgpair, layout); 3651} 3652 3653void SetLayout(layer_data *my_data, VkImage image, VkImageSubresource range, const VkImageLayout &layout) { 3654 ImageSubresourcePair imgpair = {image, true, range}; 3655 SetLayout(my_data, imgpair, layout); 3656} 3657 3658// Set the layout on the cmdbuf level 3659void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node) { 3660 pCB->imageLayoutMap[imgpair] = node; 3661 // TODO (mlentine): Maybe make vector a set? 3662 auto subresource = std::find(pCB->imageSubresourceMap[image].begin(), pCB->imageSubresourceMap[image].end(), imgpair); 3663 if (subresource == pCB->imageSubresourceMap[image].end()) { 3664 pCB->imageSubresourceMap[image].push_back(imgpair); 3665 } 3666} 3667 3668void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, ImageSubresourcePair imgpair, const VkImageLayout &layout) { 3669 // TODO (mlentine): Maybe make vector a set? 3670 if (std::find(pCB->imageSubresourceMap[image].begin(), pCB->imageSubresourceMap[image].end(), imgpair) != 3671 pCB->imageSubresourceMap[image].end()) { 3672 pCB->imageLayoutMap[imgpair].layout = layout; 3673 } else { 3674 // TODO (mlentine): Could be expensive and might need to be removed. 3675 assert(imgpair.hasSubresource); 3676 IMAGE_CMD_BUF_LAYOUT_NODE node; 3677 FindLayout(pCB, image, imgpair.subresource, node); 3678 SetLayout(pCB, image, imgpair, {node.initialLayout, layout}); 3679 } 3680} 3681 3682void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, const IMAGE_CMD_BUF_LAYOUT_NODE &node) { 3683 ImageSubresourcePair imgpair = {image, false, VkImageSubresource()}; 3684 SetLayout(pCB, image, imgpair, node); 3685} 3686 3687void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, const IMAGE_CMD_BUF_LAYOUT_NODE &node) { 3688 ImageSubresourcePair imgpair = {image, true, range}; 3689 SetLayout(pCB, image, imgpair, node); 3690} 3691 3692void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, const VkImageLayout &layout) { 3693 ImageSubresourcePair imgpair = {image, false, VkImageSubresource()}; 3694 SetLayout(pCB, image, imgpair, layout); 3695} 3696 3697void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, const VkImageLayout &layout) { 3698 ImageSubresourcePair imgpair = {image, true, range}; 3699 SetLayout(pCB, image, imgpair, layout); 3700} 3701 3702void SetLayout(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkImageView imageView, const VkImageLayout &layout) { 3703 auto image_view_data = dev_data->imageViewMap.find(imageView); 3704 assert(image_view_data != dev_data->imageViewMap.end()); 3705 const VkImage &image = image_view_data->second.image; 3706 const VkImageSubresourceRange &subRange = image_view_data->second.subresourceRange; 3707 // TODO: Do not iterate over every possibility - consolidate where possible 3708 for (uint32_t j = 0; j < subRange.levelCount; j++) { 3709 uint32_t level = subRange.baseMipLevel + j; 3710 for (uint32_t k = 0; k < subRange.layerCount; k++) { 3711 uint32_t layer = subRange.baseArrayLayer + k; 3712 VkImageSubresource sub = {subRange.aspectMask, level, layer}; 3713 SetLayout(pCB, image, sub, layout); 3714 } 3715 } 3716} 3717 3718// Verify that given imageView is valid 3719static VkBool32 validateImageView(const layer_data *my_data, const VkImageView *pImageView, const VkImageLayout imageLayout) { 3720 VkBool32 skipCall = VK_FALSE; 3721 auto ivIt = my_data->imageViewMap.find(*pImageView); 3722 if (ivIt == my_data->imageViewMap.end()) { 3723 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3724 (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", 3725 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid imageView %#" PRIxLEAST64, 3726 (uint64_t)*pImageView); 3727 } else { 3728 // Validate that imageLayout is compatible with aspectMask and image format 3729 VkImageAspectFlags aspectMask = ivIt->second.subresourceRange.aspectMask; 3730 VkImage image = ivIt->second.image; 3731 // TODO : Check here in case we have a bad image 3732 VkFormat format = VK_FORMAT_MAX_ENUM; 3733 auto imgIt = my_data->imageMap.find(image); 3734 if (imgIt != my_data->imageMap.end()) { 3735 format = (*imgIt).second.createInfo.format; 3736 } else { 3737 // Also need to check the swapchains. 3738 auto swapchainIt = my_data->device_extensions.imageToSwapchainMap.find(image); 3739 if (swapchainIt != my_data->device_extensions.imageToSwapchainMap.end()) { 3740 VkSwapchainKHR swapchain = swapchainIt->second; 3741 auto swapchain_nodeIt = my_data->device_extensions.swapchainMap.find(swapchain); 3742 if (swapchain_nodeIt != my_data->device_extensions.swapchainMap.end()) { 3743 SWAPCHAIN_NODE *pswapchain_node = swapchain_nodeIt->second; 3744 format = pswapchain_node->createInfo.imageFormat; 3745 } 3746 } 3747 } 3748 if (format == VK_FORMAT_MAX_ENUM) { 3749 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 3750 (uint64_t)image, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", 3751 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid image %#" PRIxLEAST64 3752 " in imageView %#" PRIxLEAST64, 3753 (uint64_t)image, (uint64_t)*pImageView); 3754 } else { 3755 VkBool32 ds = vk_format_is_depth_or_stencil(format); 3756 switch (imageLayout) { 3757 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: 3758 // Only Color bit must be set 3759 if ((aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) { 3760 skipCall |= 3761 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3762 (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS", 3763 "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL " 3764 "and imageView %#" PRIxLEAST64 "" 3765 " that does not have VK_IMAGE_ASPECT_COLOR_BIT set.", 3766 (uint64_t)*pImageView); 3767 } 3768 // format must NOT be DS 3769 if (ds) { 3770 skipCall |= 3771 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3772 (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", 3773 "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL " 3774 "and imageView %#" PRIxLEAST64 "" 3775 " but the image format is %s which is not a color format.", 3776 (uint64_t)*pImageView, string_VkFormat(format)); 3777 } 3778 break; 3779 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: 3780 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: 3781 // Depth or stencil bit must be set, but both must NOT be set 3782 if (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) { 3783 if (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) { 3784 // both must NOT be set 3785 skipCall |= 3786 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3787 (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS", 3788 "vkUpdateDescriptorSets: Updating descriptor with imageView %#" PRIxLEAST64 "" 3789 " that has both STENCIL and DEPTH aspects set", 3790 (uint64_t)*pImageView); 3791 } 3792 } else if (!(aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) { 3793 // Neither were set 3794 skipCall |= 3795 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3796 (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS", 3797 "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 "" 3798 " that does not have STENCIL or DEPTH aspect set.", 3799 string_VkImageLayout(imageLayout), (uint64_t)*pImageView); 3800 } 3801 // format must be DS 3802 if (!ds) { 3803 skipCall |= 3804 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3805 (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", 3806 "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 "" 3807 " but the image format is %s which is not a depth/stencil format.", 3808 string_VkImageLayout(imageLayout), (uint64_t)*pImageView, string_VkFormat(format)); 3809 } 3810 break; 3811 default: 3812 // anything to check for other layouts? 3813 break; 3814 } 3815 } 3816 } 3817 return skipCall; 3818} 3819 3820// Verify that given bufferView is valid 3821static VkBool32 validateBufferView(const layer_data *my_data, const VkBufferView *pBufferView) { 3822 VkBool32 skipCall = VK_FALSE; 3823 auto sampIt = my_data->bufferViewMap.find(*pBufferView); 3824 if (sampIt == my_data->bufferViewMap.end()) { 3825 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT, 3826 (uint64_t)*pBufferView, __LINE__, DRAWSTATE_BUFFERVIEW_DESCRIPTOR_ERROR, "DS", 3827 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid bufferView %#" PRIxLEAST64, 3828 (uint64_t)*pBufferView); 3829 } else { 3830 // TODO : Any further checks we want to do on the bufferView? 3831 } 3832 return skipCall; 3833} 3834 3835// Verify that given bufferInfo is valid 3836static VkBool32 validateBufferInfo(const layer_data *my_data, const VkDescriptorBufferInfo *pBufferInfo) { 3837 VkBool32 skipCall = VK_FALSE; 3838 auto sampIt = my_data->bufferMap.find(pBufferInfo->buffer); 3839 if (sampIt == my_data->bufferMap.end()) { 3840 skipCall |= 3841 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, 3842 (uint64_t)pBufferInfo->buffer, __LINE__, DRAWSTATE_BUFFERINFO_DESCRIPTOR_ERROR, "DS", 3843 "vkUpdateDescriptorSets: Attempt to update descriptor where bufferInfo has invalid buffer %#" PRIxLEAST64, 3844 (uint64_t)pBufferInfo->buffer); 3845 } else { 3846 // TODO : Any further checks we want to do on the bufferView? 3847 } 3848 return skipCall; 3849} 3850 3851static VkBool32 validateUpdateContents(const layer_data *my_data, const VkWriteDescriptorSet *pWDS, 3852 const VkDescriptorSetLayoutBinding *pLayoutBinding) { 3853 VkBool32 skipCall = VK_FALSE; 3854 // First verify that for the given Descriptor type, the correct DescriptorInfo data is supplied 3855 const VkSampler *pSampler = NULL; 3856 VkBool32 immutable = VK_FALSE; 3857 uint32_t i = 0; 3858 // For given update type, verify that update contents are correct 3859 switch (pWDS->descriptorType) { 3860 case VK_DESCRIPTOR_TYPE_SAMPLER: 3861 for (i = 0; i < pWDS->descriptorCount; ++i) { 3862 skipCall |= validateSampler(my_data, &(pWDS->pImageInfo[i].sampler), immutable); 3863 } 3864 break; 3865 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: 3866 for (i = 0; i < pWDS->descriptorCount; ++i) { 3867 if (NULL == pLayoutBinding->pImmutableSamplers) { 3868 pSampler = &(pWDS->pImageInfo[i].sampler); 3869 if (immutable) { 3870 skipCall |= log_msg( 3871 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, 3872 (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS", 3873 "vkUpdateDescriptorSets: Update #%u is not an immutable sampler %#" PRIxLEAST64 3874 ", but previous update(s) from this " 3875 "VkWriteDescriptorSet struct used an immutable sampler. All updates from a single struct must either " 3876 "use immutable or non-immutable samplers.", 3877 i, (uint64_t)*pSampler); 3878 } 3879 } else { 3880 if (i > 0 && !immutable) { 3881 skipCall |= log_msg( 3882 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, 3883 (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS", 3884 "vkUpdateDescriptorSets: Update #%u is an immutable sampler, but previous update(s) from this " 3885 "VkWriteDescriptorSet struct used a non-immutable sampler. All updates from a single struct must either " 3886 "use immutable or non-immutable samplers.", 3887 i); 3888 } 3889 immutable = VK_TRUE; 3890 pSampler = &(pLayoutBinding->pImmutableSamplers[i]); 3891 } 3892 skipCall |= validateSampler(my_data, pSampler, immutable); 3893 } 3894 // Intentionally fall through here to also validate image stuff 3895 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: 3896 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: 3897 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: 3898 for (i = 0; i < pWDS->descriptorCount; ++i) { 3899 skipCall |= validateImageView(my_data, &(pWDS->pImageInfo[i].imageView), pWDS->pImageInfo[i].imageLayout); 3900 } 3901 break; 3902 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: 3903 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: 3904 for (i = 0; i < pWDS->descriptorCount; ++i) { 3905 skipCall |= validateBufferView(my_data, &(pWDS->pTexelBufferView[i])); 3906 } 3907 break; 3908 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: 3909 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: 3910 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: 3911 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: 3912 for (i = 0; i < pWDS->descriptorCount; ++i) { 3913 skipCall |= validateBufferInfo(my_data, &(pWDS->pBufferInfo[i])); 3914 } 3915 break; 3916 default: 3917 break; 3918 } 3919 return skipCall; 3920} 3921// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer 3922// func_str is the name of the calling function 3923// Return VK_FALSE if no errors occur 3924// Return VK_TRUE if validation error occurs and callback returns VK_TRUE (to skip upcoming API call down the chain) 3925VkBool32 validateIdleDescriptorSet(const layer_data *my_data, VkDescriptorSet set, std::string func_str) { 3926 VkBool32 skip_call = VK_FALSE; 3927 auto set_node = my_data->setMap.find(set); 3928 if (set_node == my_data->setMap.end()) { 3929 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 3930 (uint64_t)(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS", 3931 "Cannot call %s() on descriptor set %" PRIxLEAST64 " that has not been allocated.", func_str.c_str(), 3932 (uint64_t)(set)); 3933 } else { 3934 if (set_node->second->in_use.load()) { 3935 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 3936 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)(set), __LINE__, DRAWSTATE_OBJECT_INUSE, 3937 "DS", "Cannot call %s() on descriptor set %" PRIxLEAST64 " that is in use by a command buffer.", 3938 func_str.c_str(), (uint64_t)(set)); 3939 } 3940 } 3941 return skip_call; 3942} 3943static void invalidateBoundCmdBuffers(layer_data *dev_data, const SET_NODE *pSet) { 3944 // Flag any CBs this set is bound to as INVALID 3945 for (auto cb : pSet->boundCmdBuffers) { 3946 auto cb_node = dev_data->commandBufferMap.find(cb); 3947 if (cb_node != dev_data->commandBufferMap.end()) { 3948 cb_node->second->state = CB_INVALID; 3949 } 3950 } 3951} 3952// update DS mappings based on write and copy update arrays 3953static VkBool32 dsUpdate(layer_data *my_data, VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pWDS, 3954 uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pCDS) { 3955 VkBool32 skipCall = VK_FALSE; 3956 3957 LAYOUT_NODE *pLayout = NULL; 3958 VkDescriptorSetLayoutCreateInfo *pLayoutCI = NULL; 3959 // Validate Write updates 3960 uint32_t i = 0; 3961 for (i = 0; i < descriptorWriteCount; i++) { 3962 VkDescriptorSet ds = pWDS[i].dstSet; 3963 SET_NODE *pSet = my_data->setMap[ds]; 3964 // Set being updated cannot be in-flight 3965 if ((skipCall = validateIdleDescriptorSet(my_data, ds, "VkUpdateDescriptorSets")) == VK_TRUE) 3966 return skipCall; 3967 // If set is bound to any cmdBuffers, mark them invalid 3968 invalidateBoundCmdBuffers(my_data, pSet); 3969 GENERIC_HEADER *pUpdate = (GENERIC_HEADER *)&pWDS[i]; 3970 pLayout = pSet->pLayout; 3971 // First verify valid update struct 3972 if ((skipCall = validUpdateStruct(my_data, device, pUpdate)) == VK_TRUE) { 3973 break; 3974 } 3975 uint32_t binding = 0, endIndex = 0; 3976 binding = pWDS[i].dstBinding; 3977 auto bindingToIndex = pLayout->bindingToIndexMap.find(binding); 3978 // Make sure that layout being updated has the binding being updated 3979 if (bindingToIndex == pLayout->bindingToIndexMap.end()) { 3980 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 3981 (uint64_t)(ds), __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS", 3982 "Descriptor Set %" PRIu64 " does not have binding to match " 3983 "update binding %u for update type " 3984 "%s!", 3985 (uint64_t)(ds), binding, string_VkStructureType(pUpdate->sType)); 3986 } else { 3987 // Next verify that update falls within size of given binding 3988 endIndex = getUpdateEndIndex(my_data, device, pLayout, binding, pWDS[i].dstArrayElement, pUpdate); 3989 if (getBindingEndIndex(pLayout, binding) < endIndex) { 3990 pLayoutCI = &pLayout->createInfo; 3991 string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS} "); 3992 skipCall |= 3993 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 3994 (uint64_t)(ds), __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS", 3995 "Descriptor update type of %s is out of bounds for matching binding %u in Layout w/ CI:\n%s!", 3996 string_VkStructureType(pUpdate->sType), binding, DSstr.c_str()); 3997 } else { // TODO : should we skip update on a type mismatch or force it? 3998 uint32_t startIndex; 3999 startIndex = getUpdateStartIndex(my_data, device, pLayout, binding, pWDS[i].dstArrayElement, pUpdate); 4000 // Layout bindings match w/ update, now verify that update type 4001 // & stageFlags are the same for entire update 4002 if ((skipCall = validateUpdateConsistency(my_data, device, pLayout, pUpdate, startIndex, endIndex)) == VK_FALSE) { 4003 // The update is within bounds and consistent, but need to 4004 // make sure contents make sense as well 4005 if ((skipCall = validateUpdateContents(my_data, &pWDS[i], 4006 &pLayout->createInfo.pBindings[bindingToIndex->second])) == VK_FALSE) { 4007 // Update is good. Save the update info 4008 // Create new update struct for this set's shadow copy 4009 GENERIC_HEADER *pNewNode = NULL; 4010 skipCall |= shadowUpdateNode(my_data, device, pUpdate, &pNewNode); 4011 if (NULL == pNewNode) { 4012 skipCall |= log_msg( 4013 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4014 (uint64_t)(ds), __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", 4015 "Out of memory while attempting to allocate UPDATE struct in vkUpdateDescriptors()"); 4016 } else { 4017 // Insert shadow node into LL of updates for this set 4018 pNewNode->pNext = pSet->pUpdateStructs; 4019 pSet->pUpdateStructs = pNewNode; 4020 // Now update appropriate descriptor(s) to point to new Update node 4021 for (uint32_t j = startIndex; j <= endIndex; j++) { 4022 assert(j < pSet->descriptorCount); 4023 pSet->ppDescriptors[j] = pNewNode; 4024 } 4025 } 4026 } 4027 } 4028 } 4029 } 4030 } 4031 // Now validate copy updates 4032 for (i = 0; i < descriptorCopyCount; ++i) { 4033 SET_NODE *pSrcSet = NULL, *pDstSet = NULL; 4034 LAYOUT_NODE *pSrcLayout = NULL, *pDstLayout = NULL; 4035 uint32_t srcStartIndex = 0, srcEndIndex = 0, dstStartIndex = 0, dstEndIndex = 0; 4036 // For each copy make sure that update falls within given layout and that types match 4037 pSrcSet = my_data->setMap[pCDS[i].srcSet]; 4038 pDstSet = my_data->setMap[pCDS[i].dstSet]; 4039 // Set being updated cannot be in-flight 4040 if ((skipCall = validateIdleDescriptorSet(my_data, pDstSet->set, "VkUpdateDescriptorSets")) == VK_TRUE) 4041 return skipCall; 4042 invalidateBoundCmdBuffers(my_data, pDstSet); 4043 pSrcLayout = pSrcSet->pLayout; 4044 pDstLayout = pDstSet->pLayout; 4045 // Validate that src binding is valid for src set layout 4046 if (pSrcLayout->bindingToIndexMap.find(pCDS[i].srcBinding) == pSrcLayout->bindingToIndexMap.end()) { 4047 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4048 (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS", 4049 "Copy descriptor update %u has srcBinding %u " 4050 "which is out of bounds for underlying SetLayout " 4051 "%#" PRIxLEAST64 " which only has bindings 0-%u.", 4052 i, pCDS[i].srcBinding, (uint64_t)pSrcLayout->layout, pSrcLayout->createInfo.bindingCount - 1); 4053 } else if (pDstLayout->bindingToIndexMap.find(pCDS[i].dstBinding) == pDstLayout->bindingToIndexMap.end()) { 4054 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4055 (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS", 4056 "Copy descriptor update %u has dstBinding %u " 4057 "which is out of bounds for underlying SetLayout " 4058 "%#" PRIxLEAST64 " which only has bindings 0-%u.", 4059 i, pCDS[i].dstBinding, (uint64_t)pDstLayout->layout, pDstLayout->createInfo.bindingCount - 1); 4060 } else { 4061 // Proceed with validation. Bindings are ok, but make sure update is within bounds of given layout 4062 srcEndIndex = getUpdateEndIndex(my_data, device, pSrcLayout, pCDS[i].srcBinding, pCDS[i].srcArrayElement, 4063 (const GENERIC_HEADER *)&(pCDS[i])); 4064 dstEndIndex = getUpdateEndIndex(my_data, device, pDstLayout, pCDS[i].dstBinding, pCDS[i].dstArrayElement, 4065 (const GENERIC_HEADER *)&(pCDS[i])); 4066 if (getBindingEndIndex(pSrcLayout, pCDS[i].srcBinding) < srcEndIndex) { 4067 pLayoutCI = &pSrcLayout->createInfo; 4068 string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS} "); 4069 skipCall |= 4070 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4071 (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS", 4072 "Copy descriptor src update is out of bounds for matching binding %u in Layout w/ CI:\n%s!", 4073 pCDS[i].srcBinding, DSstr.c_str()); 4074 } else if (getBindingEndIndex(pDstLayout, pCDS[i].dstBinding) < dstEndIndex) { 4075 pLayoutCI = &pDstLayout->createInfo; 4076 string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS} "); 4077 skipCall |= 4078 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4079 (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS", 4080 "Copy descriptor dest update is out of bounds for matching binding %u in Layout w/ CI:\n%s!", 4081 pCDS[i].dstBinding, DSstr.c_str()); 4082 } else { 4083 srcStartIndex = getUpdateStartIndex(my_data, device, pSrcLayout, pCDS[i].srcBinding, pCDS[i].srcArrayElement, 4084 (const GENERIC_HEADER *)&(pCDS[i])); 4085 dstStartIndex = getUpdateStartIndex(my_data, device, pDstLayout, pCDS[i].dstBinding, pCDS[i].dstArrayElement, 4086 (const GENERIC_HEADER *)&(pCDS[i])); 4087 for (uint32_t j = 0; j < pCDS[i].descriptorCount; ++j) { 4088 // For copy just make sure that the types match and then perform the update 4089 if (pSrcLayout->descriptorTypes[srcStartIndex + j] != pDstLayout->descriptorTypes[dstStartIndex + j]) { 4090 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 4091 __LINE__, DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS", 4092 "Copy descriptor update index %u, update count #%u, has src update descriptor type %s " 4093 "that does not match overlapping dest descriptor type of %s!", 4094 i, j + 1, string_VkDescriptorType(pSrcLayout->descriptorTypes[srcStartIndex + j]), 4095 string_VkDescriptorType(pDstLayout->descriptorTypes[dstStartIndex + j])); 4096 } else { 4097 // point dst descriptor at corresponding src descriptor 4098 // TODO : This may be a hole. I believe copy should be its own copy, 4099 // otherwise a subsequent write update to src will incorrectly affect the copy 4100 pDstSet->ppDescriptors[j + dstStartIndex] = pSrcSet->ppDescriptors[j + srcStartIndex]; 4101 pDstSet->pUpdateStructs = pSrcSet->pUpdateStructs; 4102 } 4103 } 4104 } 4105 } 4106 } 4107 return skipCall; 4108} 4109 4110// Verify that given pool has descriptors that are being requested for allocation. 4111// NOTE : Calls to this function should be wrapped in mutex 4112static VkBool32 validate_descriptor_availability_in_pool(layer_data *dev_data, DESCRIPTOR_POOL_NODE *pPoolNode, uint32_t count, 4113 const VkDescriptorSetLayout *pSetLayouts) { 4114 VkBool32 skipCall = VK_FALSE; 4115 uint32_t i = 0; 4116 uint32_t j = 0; 4117 4118 // Track number of descriptorSets allowable in this pool 4119 if (pPoolNode->availableSets < count) { 4120 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, 4121 reinterpret_cast<uint64_t &>(pPoolNode->pool), __LINE__, DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS", 4122 "Unable to allocate %u descriptorSets from pool %#" PRIxLEAST64 4123 ". This pool only has %d descriptorSets remaining.", 4124 count, reinterpret_cast<uint64_t &>(pPoolNode->pool), pPoolNode->availableSets); 4125 } else { 4126 pPoolNode->availableSets -= count; 4127 } 4128 4129 for (i = 0; i < count; ++i) { 4130 LAYOUT_NODE *pLayout = getLayoutNode(dev_data, pSetLayouts[i]); 4131 if (NULL == pLayout) { 4132 skipCall |= 4133 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, 4134 (uint64_t)pSetLayouts[i], __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS", 4135 "Unable to find set layout node for layout %#" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call", 4136 (uint64_t)pSetLayouts[i]); 4137 } else { 4138 uint32_t typeIndex = 0, poolSizeCount = 0; 4139 for (j = 0; j < pLayout->createInfo.bindingCount; ++j) { 4140 typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBindings[j].descriptorType); 4141 poolSizeCount = pLayout->createInfo.pBindings[j].descriptorCount; 4142 if (poolSizeCount > pPoolNode->availableDescriptorTypeCount[typeIndex]) { 4143 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 4144 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pLayout->layout, __LINE__, 4145 DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS", 4146 "Unable to allocate %u descriptors of type %s from pool %#" PRIxLEAST64 4147 ". This pool only has %d descriptors of this type remaining.", 4148 poolSizeCount, string_VkDescriptorType(pLayout->createInfo.pBindings[j].descriptorType), 4149 (uint64_t)pPoolNode->pool, pPoolNode->availableDescriptorTypeCount[typeIndex]); 4150 } else { // Decrement available descriptors of this type 4151 pPoolNode->availableDescriptorTypeCount[typeIndex] -= poolSizeCount; 4152 } 4153 } 4154 } 4155 } 4156 return skipCall; 4157} 4158 4159// Free the shadowed update node for this Set 4160// NOTE : Calls to this function should be wrapped in mutex 4161static void freeShadowUpdateTree(SET_NODE *pSet) { 4162 GENERIC_HEADER *pShadowUpdate = pSet->pUpdateStructs; 4163 pSet->pUpdateStructs = NULL; 4164 GENERIC_HEADER *pFreeUpdate = pShadowUpdate; 4165 // Clear the descriptor mappings as they will now be invalid 4166 memset(pSet->ppDescriptors, 0, pSet->descriptorCount * sizeof(GENERIC_HEADER *)); 4167 while (pShadowUpdate) { 4168 pFreeUpdate = pShadowUpdate; 4169 pShadowUpdate = (GENERIC_HEADER *)pShadowUpdate->pNext; 4170 VkWriteDescriptorSet *pWDS = NULL; 4171 switch (pFreeUpdate->sType) { 4172 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 4173 pWDS = (VkWriteDescriptorSet *)pFreeUpdate; 4174 switch (pWDS->descriptorType) { 4175 case VK_DESCRIPTOR_TYPE_SAMPLER: 4176 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: 4177 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: 4178 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { 4179 delete[] pWDS->pImageInfo; 4180 } break; 4181 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: 4182 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { 4183 delete[] pWDS->pTexelBufferView; 4184 } break; 4185 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: 4186 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: 4187 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: 4188 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { 4189 delete[] pWDS->pBufferInfo; 4190 } break; 4191 default: 4192 break; 4193 } 4194 break; 4195 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: 4196 break; 4197 default: 4198 assert(0); 4199 break; 4200 } 4201 delete pFreeUpdate; 4202 } 4203} 4204 4205// Free all DS Pools including their Sets & related sub-structs 4206// NOTE : Calls to this function should be wrapped in mutex 4207static void deletePools(layer_data *my_data) { 4208 if (my_data->descriptorPoolMap.size() <= 0) 4209 return; 4210 for (auto ii = my_data->descriptorPoolMap.begin(); ii != my_data->descriptorPoolMap.end(); ++ii) { 4211 SET_NODE *pSet = (*ii).second->pSets; 4212 SET_NODE *pFreeSet = pSet; 4213 while (pSet) { 4214 pFreeSet = pSet; 4215 pSet = pSet->pNext; 4216 // Freeing layouts handled in deleteLayouts() function 4217 // Free Update shadow struct tree 4218 freeShadowUpdateTree(pFreeSet); 4219 delete[] pFreeSet->ppDescriptors; 4220 delete pFreeSet; 4221 } 4222 delete (*ii).second; 4223 } 4224 my_data->descriptorPoolMap.clear(); 4225} 4226 4227// WARN : Once deleteLayouts() called, any layout ptrs in Pool/Set data structure will be invalid 4228// NOTE : Calls to this function should be wrapped in mutex 4229static void deleteLayouts(layer_data *my_data) { 4230 if (my_data->descriptorSetLayoutMap.size() <= 0) 4231 return; 4232 for (auto ii = my_data->descriptorSetLayoutMap.begin(); ii != my_data->descriptorSetLayoutMap.end(); ++ii) { 4233 LAYOUT_NODE *pLayout = (*ii).second; 4234 if (pLayout->createInfo.pBindings) { 4235 for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) { 4236 delete[] pLayout->createInfo.pBindings[i].pImmutableSamplers; 4237 } 4238 delete[] pLayout->createInfo.pBindings; 4239 } 4240 delete pLayout; 4241 } 4242 my_data->descriptorSetLayoutMap.clear(); 4243} 4244 4245// Currently clearing a set is removing all previous updates to that set 4246// TODO : Validate if this is correct clearing behavior 4247static void clearDescriptorSet(layer_data *my_data, VkDescriptorSet set) { 4248 SET_NODE *pSet = getSetNode(my_data, set); 4249 if (!pSet) { 4250 // TODO : Return error 4251 } else { 4252 freeShadowUpdateTree(pSet); 4253 } 4254} 4255 4256static void clearDescriptorPool(layer_data *my_data, const VkDevice device, const VkDescriptorPool pool, 4257 VkDescriptorPoolResetFlags flags) { 4258 DESCRIPTOR_POOL_NODE *pPool = getPoolNode(my_data, pool); 4259 if (!pPool) { 4260 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, 4261 (uint64_t)pool, __LINE__, DRAWSTATE_INVALID_POOL, "DS", 4262 "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkResetDescriptorPool() call", (uint64_t)pool); 4263 } else { 4264 // TODO: validate flags 4265 // For every set off of this pool, clear it 4266 SET_NODE *pSet = pPool->pSets; 4267 while (pSet) { 4268 clearDescriptorSet(my_data, pSet->set); 4269 pSet = pSet->pNext; 4270 } 4271 // Reset available count to max count for this pool 4272 for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) { 4273 pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i]; 4274 } 4275 } 4276} 4277 4278// For given CB object, fetch associated CB Node from map 4279static GLOBAL_CB_NODE *getCBNode(layer_data *my_data, const VkCommandBuffer cb) { 4280 if (my_data->commandBufferMap.count(cb) == 0) { 4281 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 4282 reinterpret_cast<const uint64_t &>(cb), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 4283 "Attempt to use CommandBuffer %#" PRIxLEAST64 " that doesn't exist!", (uint64_t)(cb)); 4284 return NULL; 4285 } 4286 return my_data->commandBufferMap[cb]; 4287} 4288 4289// Free all CB Nodes 4290// NOTE : Calls to this function should be wrapped in mutex 4291static void deleteCommandBuffers(layer_data *my_data) { 4292 if (my_data->commandBufferMap.size() <= 0) { 4293 return; 4294 } 4295 for (auto ii = my_data->commandBufferMap.begin(); ii != my_data->commandBufferMap.end(); ++ii) { 4296 delete (*ii).second; 4297 } 4298 my_data->commandBufferMap.clear(); 4299} 4300 4301static VkBool32 report_error_no_cb_begin(const layer_data *dev_data, const VkCommandBuffer cb, const char *caller_name) { 4302 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 4303 (uint64_t)cb, __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS", 4304 "You must call vkBeginCommandBuffer() before this call to %s", caller_name); 4305} 4306 4307VkBool32 validateCmdsInCmdBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) { 4308 if (!pCB->activeRenderPass) 4309 return VK_FALSE; 4310 VkBool32 skip_call = VK_FALSE; 4311 if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS && cmd_type != CMD_EXECUTECOMMANDS) { 4312 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4313 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 4314 "Commands cannot be called in a subpass using secondary command buffers."); 4315 } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) { 4316 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4317 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 4318 "vkCmdExecuteCommands() cannot be called in a subpass using inline commands."); 4319 } 4320 return skip_call; 4321} 4322 4323static bool checkGraphicsBit(const layer_data *my_data, VkQueueFlags flags, const char *name) { 4324 if (!(flags & VK_QUEUE_GRAPHICS_BIT)) 4325 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4326 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 4327 "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name); 4328 return false; 4329} 4330 4331static bool checkComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) { 4332 if (!(flags & VK_QUEUE_COMPUTE_BIT)) 4333 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4334 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 4335 "Cannot call %s on a command buffer allocated from a pool without compute capabilities.", name); 4336 return false; 4337} 4338 4339static bool checkGraphicsOrComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) { 4340 if (!((flags & VK_QUEUE_GRAPHICS_BIT) || (flags & VK_QUEUE_COMPUTE_BIT))) 4341 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4342 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 4343 "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name); 4344 return false; 4345} 4346 4347// Add specified CMD to the CmdBuffer in given pCB, flagging errors if CB is not 4348// in the recording state or if there's an issue with the Cmd ordering 4349static VkBool32 addCmd(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name) { 4350 VkBool32 skipCall = VK_FALSE; 4351 auto pool_data = my_data->commandPoolMap.find(pCB->createInfo.commandPool); 4352 if (pool_data != my_data->commandPoolMap.end()) { 4353 VkQueueFlags flags = my_data->physDevProperties.queue_family_properties[pool_data->second.queueFamilyIndex].queueFlags; 4354 switch (cmd) { 4355 case CMD_BINDPIPELINE: 4356 case CMD_BINDPIPELINEDELTA: 4357 case CMD_BINDDESCRIPTORSETS: 4358 case CMD_FILLBUFFER: 4359 case CMD_CLEARCOLORIMAGE: 4360 case CMD_SETEVENT: 4361 case CMD_RESETEVENT: 4362 case CMD_WAITEVENTS: 4363 case CMD_BEGINQUERY: 4364 case CMD_ENDQUERY: 4365 case CMD_RESETQUERYPOOL: 4366 case CMD_COPYQUERYPOOLRESULTS: 4367 case CMD_WRITETIMESTAMP: 4368 skipCall |= checkGraphicsOrComputeBit(my_data, flags, cmdTypeToString(cmd).c_str()); 4369 break; 4370 case CMD_SETVIEWPORTSTATE: 4371 case CMD_SETSCISSORSTATE: 4372 case CMD_SETLINEWIDTHSTATE: 4373 case CMD_SETDEPTHBIASSTATE: 4374 case CMD_SETBLENDSTATE: 4375 case CMD_SETDEPTHBOUNDSSTATE: 4376 case CMD_SETSTENCILREADMASKSTATE: 4377 case CMD_SETSTENCILWRITEMASKSTATE: 4378 case CMD_SETSTENCILREFERENCESTATE: 4379 case CMD_BINDINDEXBUFFER: 4380 case CMD_BINDVERTEXBUFFER: 4381 case CMD_DRAW: 4382 case CMD_DRAWINDEXED: 4383 case CMD_DRAWINDIRECT: 4384 case CMD_DRAWINDEXEDINDIRECT: 4385 case CMD_BLITIMAGE: 4386 case CMD_CLEARATTACHMENTS: 4387 case CMD_CLEARDEPTHSTENCILIMAGE: 4388 case CMD_RESOLVEIMAGE: 4389 case CMD_BEGINRENDERPASS: 4390 case CMD_NEXTSUBPASS: 4391 case CMD_ENDRENDERPASS: 4392 skipCall |= checkGraphicsBit(my_data, flags, cmdTypeToString(cmd).c_str()); 4393 break; 4394 case CMD_DISPATCH: 4395 case CMD_DISPATCHINDIRECT: 4396 skipCall |= checkComputeBit(my_data, flags, cmdTypeToString(cmd).c_str()); 4397 break; 4398 case CMD_COPYBUFFER: 4399 case CMD_COPYIMAGE: 4400 case CMD_COPYBUFFERTOIMAGE: 4401 case CMD_COPYIMAGETOBUFFER: 4402 case CMD_CLONEIMAGEDATA: 4403 case CMD_UPDATEBUFFER: 4404 case CMD_PIPELINEBARRIER: 4405 case CMD_EXECUTECOMMANDS: 4406 break; 4407 default: 4408 break; 4409 } 4410 } 4411 if (pCB->state != CB_RECORDING) { 4412 skipCall |= report_error_no_cb_begin(my_data, pCB->commandBuffer, caller_name); 4413 skipCall |= validateCmdsInCmdBuffer(my_data, pCB, cmd); 4414 CMD_NODE cmdNode = {}; 4415 // init cmd node and append to end of cmd LL 4416 cmdNode.cmdNumber = ++pCB->numCmds; 4417 cmdNode.type = cmd; 4418 pCB->cmds.push_back(cmdNode); 4419 } 4420 return skipCall; 4421} 4422// Reset the command buffer state 4423// Maintain the createInfo and set state to CB_NEW, but clear all other state 4424static void resetCB(layer_data *my_data, const VkCommandBuffer cb) { 4425 GLOBAL_CB_NODE *pCB = my_data->commandBufferMap[cb]; 4426 if (pCB) { 4427 pCB->cmds.clear(); 4428 // Reset CB state (note that createInfo is not cleared) 4429 pCB->commandBuffer = cb; 4430 memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo)); 4431 memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo)); 4432 pCB->numCmds = 0; 4433 memset(pCB->drawCount, 0, NUM_DRAW_TYPES * sizeof(uint64_t)); 4434 pCB->state = CB_NEW; 4435 pCB->submitCount = 0; 4436 pCB->status = 0; 4437 pCB->viewports.clear(); 4438 pCB->scissors.clear(); 4439 for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) { 4440 // Before clearing lastBoundState, remove any CB bindings from all uniqueBoundSets 4441 for (auto set : pCB->lastBound[i].uniqueBoundSets) { 4442 auto set_node = my_data->setMap.find(set); 4443 if (set_node != my_data->setMap.end()) { 4444 set_node->second->boundCmdBuffers.erase(pCB->commandBuffer); 4445 } 4446 } 4447 pCB->lastBound[i].reset(); 4448 } 4449 memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo)); 4450 pCB->activeRenderPass = 0; 4451 pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE; 4452 pCB->activeSubpass = 0; 4453 pCB->framebuffer = 0; 4454 pCB->fenceId = 0; 4455 pCB->lastSubmittedFence = VK_NULL_HANDLE; 4456 pCB->lastSubmittedQueue = VK_NULL_HANDLE; 4457 pCB->destroyedSets.clear(); 4458 pCB->updatedSets.clear(); 4459 pCB->destroyedFramebuffers.clear(); 4460 pCB->waitedEvents.clear(); 4461 pCB->semaphores.clear(); 4462 pCB->events.clear(); 4463 pCB->waitedEventsBeforeQueryReset.clear(); 4464 pCB->queryToStateMap.clear(); 4465 pCB->activeQueries.clear(); 4466 pCB->startedQueries.clear(); 4467 pCB->imageLayoutMap.clear(); 4468 pCB->eventToStageMap.clear(); 4469 pCB->drawData.clear(); 4470 pCB->currentDrawData.buffers.clear(); 4471 pCB->primaryCommandBuffer = VK_NULL_HANDLE; 4472 pCB->secondaryCommandBuffers.clear(); 4473 pCB->activeDescriptorSets.clear(); 4474 pCB->validate_functions.clear(); 4475 pCB->pMemObjList.clear(); 4476 pCB->eventUpdates.clear(); 4477 } 4478} 4479 4480// Set PSO-related status bits for CB, including dynamic state set via PSO 4481static void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_NODE *pPipe) { 4482 for (auto const & att : pPipe->attachments) { 4483 if (0 != att.colorWriteMask) { 4484 pCB->status |= CBSTATUS_COLOR_BLEND_WRITE_ENABLE; 4485 } 4486 } 4487 if (pPipe->dsStateCI.depthWriteEnable) { 4488 pCB->status |= CBSTATUS_DEPTH_WRITE_ENABLE; 4489 } 4490 if (pPipe->dsStateCI.stencilTestEnable) { 4491 pCB->status |= CBSTATUS_STENCIL_TEST_ENABLE; 4492 } 4493 // Account for any dynamic state not set via this PSO 4494 if (!pPipe->dynStateCI.dynamicStateCount) { // All state is static 4495 pCB->status = CBSTATUS_ALL; 4496 } else { 4497 // First consider all state on 4498 // Then unset any state that's noted as dynamic in PSO 4499 // Finally OR that into CB statemask 4500 CBStatusFlags psoDynStateMask = CBSTATUS_ALL; 4501 for (uint32_t i = 0; i < pPipe->dynStateCI.dynamicStateCount; i++) { 4502 switch (pPipe->dynStateCI.pDynamicStates[i]) { 4503 case VK_DYNAMIC_STATE_VIEWPORT: 4504 psoDynStateMask &= ~CBSTATUS_VIEWPORT_SET; 4505 break; 4506 case VK_DYNAMIC_STATE_SCISSOR: 4507 psoDynStateMask &= ~CBSTATUS_SCISSOR_SET; 4508 break; 4509 case VK_DYNAMIC_STATE_LINE_WIDTH: 4510 psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET; 4511 break; 4512 case VK_DYNAMIC_STATE_DEPTH_BIAS: 4513 psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET; 4514 break; 4515 case VK_DYNAMIC_STATE_BLEND_CONSTANTS: 4516 psoDynStateMask &= ~CBSTATUS_BLEND_SET; 4517 break; 4518 case VK_DYNAMIC_STATE_DEPTH_BOUNDS: 4519 psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET; 4520 break; 4521 case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK: 4522 psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET; 4523 break; 4524 case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK: 4525 psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET; 4526 break; 4527 case VK_DYNAMIC_STATE_STENCIL_REFERENCE: 4528 psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET; 4529 break; 4530 default: 4531 // TODO : Flag error here 4532 break; 4533 } 4534 } 4535 pCB->status |= psoDynStateMask; 4536 } 4537} 4538 4539// Print the last bound Gfx Pipeline 4540static VkBool32 printPipeline(layer_data *my_data, const VkCommandBuffer cb) { 4541 VkBool32 skipCall = VK_FALSE; 4542 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb); 4543 if (pCB) { 4544 PIPELINE_NODE *pPipeTrav = getPipeline(my_data, pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline); 4545 if (!pPipeTrav) { 4546 // nothing to print 4547 } else { 4548 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 4549 __LINE__, DRAWSTATE_NONE, "DS", "%s", 4550 vk_print_vkgraphicspipelinecreateinfo(&pPipeTrav->graphicsPipelineCI, "{DS}").c_str()); 4551 } 4552 } 4553 return skipCall; 4554} 4555 4556static void printCB(layer_data *my_data, const VkCommandBuffer cb) { 4557 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb); 4558 if (pCB && pCB->cmds.size() > 0) { 4559 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4560 DRAWSTATE_NONE, "DS", "Cmds in CB %p", (void *)cb); 4561 vector<CMD_NODE> cmds = pCB->cmds; 4562 for (auto ii = cmds.begin(); ii != cmds.end(); ++ii) { 4563 // TODO : Need to pass cb as srcObj here 4564 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 4565 __LINE__, DRAWSTATE_NONE, "DS", " CMD#%" PRIu64 ": %s", (*ii).cmdNumber, cmdTypeToString((*ii).type).c_str()); 4566 } 4567 } else { 4568 // Nothing to print 4569 } 4570} 4571 4572static VkBool32 synchAndPrintDSConfig(layer_data *my_data, const VkCommandBuffer cb) { 4573 VkBool32 skipCall = VK_FALSE; 4574 if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) { 4575 return skipCall; 4576 } 4577 skipCall |= printPipeline(my_data, cb); 4578 return skipCall; 4579} 4580 4581// Flags validation error if the associated call is made inside a render pass. The apiName 4582// routine should ONLY be called outside a render pass. 4583static VkBool32 insideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) { 4584 VkBool32 inside = VK_FALSE; 4585 if (pCB->activeRenderPass) { 4586 inside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 4587 (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS", 4588 "%s: It is invalid to issue this call inside an active render pass (%#" PRIxLEAST64 ")", apiName, 4589 (uint64_t)pCB->activeRenderPass); 4590 } 4591 return inside; 4592} 4593 4594// Flags validation error if the associated call is made outside a render pass. The apiName 4595// routine should ONLY be called inside a render pass. 4596static VkBool32 outsideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) { 4597 VkBool32 outside = VK_FALSE; 4598 if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) || 4599 ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) && 4600 !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) { 4601 outside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 4602 (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS", 4603 "%s: This call must be issued inside an active render pass.", apiName); 4604 } 4605 return outside; 4606} 4607 4608static void init_core_validation(layer_data *my_data, const VkAllocationCallbacks *pAllocator) { 4609 4610 layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_core_validation"); 4611 4612 if (!globalLockInitialized) { 4613 loader_platform_thread_create_mutex(&globalLock); 4614 globalLockInitialized = 1; 4615 } 4616#if MTMERGESOURCE 4617 // Zero out memory property data 4618 memset(&memProps, 0, sizeof(VkPhysicalDeviceMemoryProperties)); 4619#endif 4620} 4621 4622VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 4623vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) { 4624 VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); 4625 4626 assert(chain_info->u.pLayerInfo); 4627 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; 4628 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance"); 4629 if (fpCreateInstance == NULL) 4630 return VK_ERROR_INITIALIZATION_FAILED; 4631 4632 // Advance the link info for the next element on the chain 4633 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; 4634 4635 VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance); 4636 if (result != VK_SUCCESS) 4637 return result; 4638 4639 layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map); 4640 my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable; 4641 layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr); 4642 4643 my_data->report_data = debug_report_create_instance(my_data->instance_dispatch_table, *pInstance, 4644 pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames); 4645 4646 init_core_validation(my_data, pAllocator); 4647 4648 ValidateLayerOrdering(*pCreateInfo); 4649 4650 return result; 4651} 4652 4653/* hook DestroyInstance to remove tableInstanceMap entry */ 4654VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) { 4655 // TODOSC : Shouldn't need any customization here 4656 dispatch_key key = get_dispatch_key(instance); 4657 // TBD: Need any locking this early, in case this function is called at the 4658 // same time by more than one thread? 4659 layer_data *my_data = get_my_data_ptr(key, layer_data_map); 4660 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; 4661 pTable->DestroyInstance(instance, pAllocator); 4662 4663 loader_platform_thread_lock_mutex(&globalLock); 4664 // Clean up logging callback, if any 4665 while (my_data->logging_callback.size() > 0) { 4666 VkDebugReportCallbackEXT callback = my_data->logging_callback.back(); 4667 layer_destroy_msg_callback(my_data->report_data, callback, pAllocator); 4668 my_data->logging_callback.pop_back(); 4669 } 4670 4671 layer_debug_report_destroy_instance(my_data->report_data); 4672 delete my_data->instance_dispatch_table; 4673 layer_data_map.erase(key); 4674 loader_platform_thread_unlock_mutex(&globalLock); 4675 if (layer_data_map.empty()) { 4676 // Release mutex when destroying last instance. 4677 loader_platform_thread_delete_mutex(&globalLock); 4678 globalLockInitialized = 0; 4679 } 4680} 4681 4682static void createDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) { 4683 uint32_t i; 4684 // TBD: Need any locking, in case this function is called at the same time 4685 // by more than one thread? 4686 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 4687 dev_data->device_extensions.wsi_enabled = false; 4688 4689 VkLayerDispatchTable *pDisp = dev_data->device_dispatch_table; 4690 PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr; 4691 pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpa(device, "vkCreateSwapchainKHR"); 4692 pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)gpa(device, "vkDestroySwapchainKHR"); 4693 pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)gpa(device, "vkGetSwapchainImagesKHR"); 4694 pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)gpa(device, "vkAcquireNextImageKHR"); 4695 pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR)gpa(device, "vkQueuePresentKHR"); 4696 4697 for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) { 4698 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) 4699 dev_data->device_extensions.wsi_enabled = true; 4700 } 4701} 4702 4703VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, 4704 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) { 4705 VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); 4706 4707 assert(chain_info->u.pLayerInfo); 4708 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; 4709 PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr; 4710 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice"); 4711 if (fpCreateDevice == NULL) { 4712 return VK_ERROR_INITIALIZATION_FAILED; 4713 } 4714 4715 // Advance the link info for the next element on the chain 4716 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; 4717 4718 VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice); 4719 if (result != VK_SUCCESS) { 4720 return result; 4721 } 4722 4723 loader_platform_thread_lock_mutex(&globalLock); 4724 layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map); 4725 layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map); 4726 4727 // Setup device dispatch table 4728 my_device_data->device_dispatch_table = new VkLayerDispatchTable; 4729 layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr); 4730 4731 my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice); 4732 createDeviceRegisterExtensions(pCreateInfo, *pDevice); 4733 // Get physical device limits for this device 4734 my_instance_data->instance_dispatch_table->GetPhysicalDeviceProperties(gpu, &(my_device_data->physDevProperties.properties)); 4735 uint32_t count; 4736 my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr); 4737 my_device_data->physDevProperties.queue_family_properties.resize(count); 4738 my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties( 4739 gpu, &count, &my_device_data->physDevProperties.queue_family_properties[0]); 4740 // TODO: device limits should make sure these are compatible 4741 if (pCreateInfo->pEnabledFeatures) { 4742 my_device_data->physDevProperties.features = *pCreateInfo->pEnabledFeatures; 4743 } else { 4744 memset(&my_device_data->physDevProperties.features, 0, sizeof(VkPhysicalDeviceFeatures)); 4745 } 4746 loader_platform_thread_unlock_mutex(&globalLock); 4747 4748 ValidateLayerOrdering(*pCreateInfo); 4749 4750 return result; 4751} 4752 4753// prototype 4754static void deleteRenderPasses(layer_data *); 4755VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) { 4756 // TODOSC : Shouldn't need any customization here 4757 dispatch_key key = get_dispatch_key(device); 4758 layer_data *dev_data = get_my_data_ptr(key, layer_data_map); 4759 // Free all the memory 4760 loader_platform_thread_lock_mutex(&globalLock); 4761 deletePipelines(dev_data); 4762 deleteRenderPasses(dev_data); 4763 deleteCommandBuffers(dev_data); 4764 deletePools(dev_data); 4765 deleteLayouts(dev_data); 4766 dev_data->imageViewMap.clear(); 4767 dev_data->imageMap.clear(); 4768 dev_data->imageSubresourceMap.clear(); 4769 dev_data->imageLayoutMap.clear(); 4770 dev_data->bufferViewMap.clear(); 4771 dev_data->bufferMap.clear(); 4772 loader_platform_thread_unlock_mutex(&globalLock); 4773#if MTMERGESOURCE 4774 VkBool32 skipCall = VK_FALSE; 4775 loader_platform_thread_lock_mutex(&globalLock); 4776 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 4777 (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "Printing List details prior to vkDestroyDevice()"); 4778 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 4779 (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "================================================"); 4780 print_mem_list(dev_data, device); 4781 printCBList(dev_data, device); 4782 delete_cmd_buf_info_list(dev_data); 4783 // Report any memory leaks 4784 DEVICE_MEM_INFO *pInfo = NULL; 4785 if (dev_data->memObjMap.size() > 0) { 4786 for (auto ii = dev_data->memObjMap.begin(); ii != dev_data->memObjMap.end(); ++ii) { 4787 pInfo = &(*ii).second; 4788 if (pInfo->allocInfo.allocationSize != 0) { 4789 // Valid Usage: All child objects created on device must have been destroyed prior to destroying device 4790 skipCall |= 4791 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 4792 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pInfo->mem, __LINE__, MEMTRACK_MEMORY_LEAK, 4793 "MEM", "Mem Object %" PRIu64 " has not been freed. You should clean up this memory by calling " 4794 "vkFreeMemory(%" PRIu64 ") prior to vkDestroyDevice().", 4795 (uint64_t)(pInfo->mem), (uint64_t)(pInfo->mem)); 4796 } 4797 } 4798 } 4799 // Queues persist until device is destroyed 4800 delete_queue_info_list(dev_data); 4801 layer_debug_report_destroy_device(device); 4802 loader_platform_thread_unlock_mutex(&globalLock); 4803 4804#if DISPATCH_MAP_DEBUG 4805 fprintf(stderr, "Device: %p, key: %p\n", device, key); 4806#endif 4807 VkLayerDispatchTable *pDisp = dev_data->device_dispatch_table; 4808 if (VK_FALSE == skipCall) { 4809 pDisp->DestroyDevice(device, pAllocator); 4810 } 4811#else 4812 dev_data->device_dispatch_table->DestroyDevice(device, pAllocator); 4813#endif 4814 delete dev_data->device_dispatch_table; 4815 layer_data_map.erase(key); 4816} 4817 4818#if MTMERGESOURCE 4819VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 4820vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties) { 4821 layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map); 4822 VkLayerInstanceDispatchTable *pInstanceTable = my_data->instance_dispatch_table; 4823 pInstanceTable->GetPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties); 4824 memcpy(&memProps, pMemoryProperties, sizeof(VkPhysicalDeviceMemoryProperties)); 4825} 4826#endif 4827 4828static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}}; 4829 4830VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 4831vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties) { 4832 return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties); 4833} 4834 4835VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 4836vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) { 4837 return util_GetLayerProperties(ARRAY_SIZE(cv_global_layers), cv_global_layers, pCount, pProperties); 4838} 4839 4840// TODO: Why does this exist - can we just use global? 4841static const VkLayerProperties cv_device_layers[] = {{ 4842 "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer", 4843}}; 4844 4845VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, 4846 const char *pLayerName, uint32_t *pCount, 4847 VkExtensionProperties *pProperties) { 4848 if (pLayerName == NULL) { 4849 dispatch_key key = get_dispatch_key(physicalDevice); 4850 layer_data *my_data = get_my_data_ptr(key, layer_data_map); 4851 return my_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties); 4852 } else { 4853 return util_GetExtensionProperties(0, NULL, pCount, pProperties); 4854 } 4855} 4856 4857VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 4858vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties) { 4859 /* draw_state physical device layers are the same as global */ 4860 return util_GetLayerProperties(ARRAY_SIZE(cv_device_layers), cv_device_layers, pCount, pProperties); 4861} 4862 4863// This validates that the initial layout specified in the command buffer for 4864// the IMAGE is the same 4865// as the global IMAGE layout 4866VkBool32 ValidateCmdBufImageLayouts(VkCommandBuffer cmdBuffer) { 4867 VkBool32 skip_call = VK_FALSE; 4868 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 4869 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 4870 for (auto cb_image_data : pCB->imageLayoutMap) { 4871 VkImageLayout imageLayout; 4872 if (!FindLayout(dev_data, cb_image_data.first, imageLayout)) { 4873 skip_call |= 4874 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 4875 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot submit cmd buffer using deleted image %" PRIu64 ".", 4876 reinterpret_cast<const uint64_t &>(cb_image_data.first)); 4877 } else { 4878 if (cb_image_data.second.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) { 4879 // TODO: Set memory invalid which is in mem_tracker currently 4880 } else if (imageLayout != cb_image_data.second.initialLayout) { 4881 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 4882 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, 4883 "DS", "Cannot submit cmd buffer using image with layout %s when " 4884 "first use is %s.", 4885 string_VkImageLayout(imageLayout), string_VkImageLayout(cb_image_data.second.initialLayout)); 4886 } 4887 SetLayout(dev_data, cb_image_data.first, cb_image_data.second.layout); 4888 } 4889 } 4890 return skip_call; 4891} 4892// Track which resources are in-flight by atomically incrementing their "in_use" count 4893VkBool32 validateAndIncrementResources(layer_data *my_data, GLOBAL_CB_NODE *pCB) { 4894 VkBool32 skip_call = VK_FALSE; 4895 for (auto drawDataElement : pCB->drawData) { 4896 for (auto buffer : drawDataElement.buffers) { 4897 auto buffer_data = my_data->bufferMap.find(buffer); 4898 if (buffer_data == my_data->bufferMap.end()) { 4899 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, 4900 (uint64_t)(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS", 4901 "Cannot submit cmd buffer using deleted buffer %" PRIu64 ".", (uint64_t)(buffer)); 4902 } else { 4903 buffer_data->second.in_use.fetch_add(1); 4904 } 4905 } 4906 } 4907 for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) { 4908 for (auto set : pCB->lastBound[i].uniqueBoundSets) { 4909 auto setNode = my_data->setMap.find(set); 4910 if (setNode == my_data->setMap.end()) { 4911 skip_call |= 4912 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4913 (uint64_t)(set), __LINE__, DRAWSTATE_INVALID_DESCRIPTOR_SET, "DS", 4914 "Cannot submit cmd buffer using deleted descriptor set %" PRIu64 ".", (uint64_t)(set)); 4915 } else { 4916 setNode->second->in_use.fetch_add(1); 4917 } 4918 } 4919 } 4920 for (auto semaphore : pCB->semaphores) { 4921 auto semaphoreNode = my_data->semaphoreMap.find(semaphore); 4922 if (semaphoreNode == my_data->semaphoreMap.end()) { 4923 skip_call |= 4924 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4925 reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS", 4926 "Cannot submit cmd buffer using deleted semaphore %" PRIu64 ".", reinterpret_cast<uint64_t &>(semaphore)); 4927 } else { 4928 semaphoreNode->second.in_use.fetch_add(1); 4929 } 4930 } 4931 for (auto event : pCB->events) { 4932 auto eventNode = my_data->eventMap.find(event); 4933 if (eventNode == my_data->eventMap.end()) { 4934 skip_call |= 4935 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4936 reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS", 4937 "Cannot submit cmd buffer using deleted event %" PRIu64 ".", reinterpret_cast<uint64_t &>(event)); 4938 } else { 4939 eventNode->second.in_use.fetch_add(1); 4940 } 4941 } 4942 return skip_call; 4943} 4944 4945void decrementResources(layer_data *my_data, VkCommandBuffer cmdBuffer) { 4946 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer); 4947 for (auto drawDataElement : pCB->drawData) { 4948 for (auto buffer : drawDataElement.buffers) { 4949 auto buffer_data = my_data->bufferMap.find(buffer); 4950 if (buffer_data != my_data->bufferMap.end()) { 4951 buffer_data->second.in_use.fetch_sub(1); 4952 } 4953 } 4954 } 4955 for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) { 4956 for (auto set : pCB->lastBound[i].uniqueBoundSets) { 4957 auto setNode = my_data->setMap.find(set); 4958 if (setNode != my_data->setMap.end()) { 4959 setNode->second->in_use.fetch_sub(1); 4960 } 4961 } 4962 } 4963 for (auto semaphore : pCB->semaphores) { 4964 auto semaphoreNode = my_data->semaphoreMap.find(semaphore); 4965 if (semaphoreNode != my_data->semaphoreMap.end()) { 4966 semaphoreNode->second.in_use.fetch_sub(1); 4967 } 4968 } 4969 for (auto event : pCB->events) { 4970 auto eventNode = my_data->eventMap.find(event); 4971 if (eventNode != my_data->eventMap.end()) { 4972 eventNode->second.in_use.fetch_sub(1); 4973 } 4974 } 4975 for (auto queryStatePair : pCB->queryToStateMap) { 4976 my_data->queryToStateMap[queryStatePair.first] = queryStatePair.second; 4977 } 4978 for (auto eventStagePair : pCB->eventToStageMap) { 4979 my_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second; 4980 } 4981} 4982 4983void decrementResources(layer_data *my_data, uint32_t fenceCount, const VkFence *pFences) { 4984 for (uint32_t i = 0; i < fenceCount; ++i) { 4985 auto fence_data = my_data->fenceMap.find(pFences[i]); 4986 if (fence_data == my_data->fenceMap.end() || !fence_data->second.needsSignaled) 4987 return; 4988 fence_data->second.needsSignaled = false; 4989 fence_data->second.in_use.fetch_sub(1); 4990 decrementResources(my_data, fence_data->second.priorFences.size(), fence_data->second.priorFences.data()); 4991 for (auto cmdBuffer : fence_data->second.cmdBuffers) { 4992 decrementResources(my_data, cmdBuffer); 4993 } 4994 } 4995} 4996 4997void decrementResources(layer_data *my_data, VkQueue queue) { 4998 auto queue_data = my_data->queueMap.find(queue); 4999 if (queue_data != my_data->queueMap.end()) { 5000 for (auto cmdBuffer : queue_data->second.untrackedCmdBuffers) { 5001 decrementResources(my_data, cmdBuffer); 5002 } 5003 queue_data->second.untrackedCmdBuffers.clear(); 5004 decrementResources(my_data, queue_data->second.lastFences.size(), queue_data->second.lastFences.data()); 5005 } 5006} 5007 5008void updateTrackedCommandBuffers(layer_data *dev_data, VkQueue queue, VkQueue other_queue, VkFence fence) { 5009 if (queue == other_queue) { 5010 return; 5011 } 5012 auto queue_data = dev_data->queueMap.find(queue); 5013 auto other_queue_data = dev_data->queueMap.find(other_queue); 5014 if (queue_data == dev_data->queueMap.end() || other_queue_data == dev_data->queueMap.end()) { 5015 return; 5016 } 5017 for (auto fence : other_queue_data->second.lastFences) { 5018 queue_data->second.lastFences.push_back(fence); 5019 } 5020 if (fence != VK_NULL_HANDLE) { 5021 auto fence_data = dev_data->fenceMap.find(fence); 5022 if (fence_data == dev_data->fenceMap.end()) { 5023 return; 5024 } 5025 for (auto cmdbuffer : other_queue_data->second.untrackedCmdBuffers) { 5026 fence_data->second.cmdBuffers.push_back(cmdbuffer); 5027 } 5028 other_queue_data->second.untrackedCmdBuffers.clear(); 5029 } else { 5030 for (auto cmdbuffer : other_queue_data->second.untrackedCmdBuffers) { 5031 queue_data->second.untrackedCmdBuffers.push_back(cmdbuffer); 5032 } 5033 other_queue_data->second.untrackedCmdBuffers.clear(); 5034 } 5035 for (auto eventStagePair : other_queue_data->second.eventToStageMap) { 5036 queue_data->second.eventToStageMap[eventStagePair.first] = eventStagePair.second; 5037 } 5038} 5039 5040void trackCommandBuffers(layer_data *my_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) { 5041 auto queue_data = my_data->queueMap.find(queue); 5042 if (fence != VK_NULL_HANDLE) { 5043 vector<VkFence> prior_fences; 5044 auto fence_data = my_data->fenceMap.find(fence); 5045 if (fence_data == my_data->fenceMap.end()) { 5046 return; 5047 } 5048 if (queue_data != my_data->queueMap.end()) { 5049 prior_fences = queue_data->second.lastFences; 5050 queue_data->second.lastFences.clear(); 5051 queue_data->second.lastFences.push_back(fence); 5052 for (auto cmdbuffer : queue_data->second.untrackedCmdBuffers) { 5053 fence_data->second.cmdBuffers.push_back(cmdbuffer); 5054 } 5055 queue_data->second.untrackedCmdBuffers.clear(); 5056 } 5057 fence_data->second.cmdBuffers.clear(); 5058 fence_data->second.priorFences = prior_fences; 5059 fence_data->second.needsSignaled = true; 5060 fence_data->second.queue = queue; 5061 fence_data->second.in_use.fetch_add(1); 5062 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5063 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5064 for (uint32_t i = 0; i < submit->commandBufferCount; ++i) { 5065 for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) { 5066 fence_data->second.cmdBuffers.push_back(secondaryCmdBuffer); 5067 } 5068 fence_data->second.cmdBuffers.push_back(submit->pCommandBuffers[i]); 5069 } 5070 } 5071 } else { 5072 if (queue_data != my_data->queueMap.end()) { 5073 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5074 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5075 for (uint32_t i = 0; i < submit->commandBufferCount; ++i) { 5076 for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) { 5077 queue_data->second.untrackedCmdBuffers.push_back(secondaryCmdBuffer); 5078 } 5079 queue_data->second.untrackedCmdBuffers.push_back(submit->pCommandBuffers[i]); 5080 } 5081 } 5082 } 5083 } 5084 if (queue_data != my_data->queueMap.end()) { 5085 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5086 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5087 for (uint32_t i = 0; i < submit->commandBufferCount; ++i) { 5088 // Add cmdBuffers to both the global set and queue set 5089 for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) { 5090 my_data->globalInFlightCmdBuffers.insert(secondaryCmdBuffer); 5091 queue_data->second.inFlightCmdBuffers.insert(secondaryCmdBuffer); 5092 } 5093 my_data->globalInFlightCmdBuffers.insert(submit->pCommandBuffers[i]); 5094 queue_data->second.inFlightCmdBuffers.insert(submit->pCommandBuffers[i]); 5095 } 5096 } 5097 } 5098} 5099 5100bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB) { 5101 bool skip_call = false; 5102 if (dev_data->globalInFlightCmdBuffers.count(pCB->commandBuffer) && 5103 !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) { 5104 skip_call |= 5105 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 5106 __LINE__, DRAWSTATE_INVALID_FENCE, "DS", "Command Buffer %#" PRIx64 " is already in use and is not marked " 5107 "for simultaneous use.", 5108 reinterpret_cast<uint64_t>(pCB->commandBuffer)); 5109 } 5110 return skip_call; 5111} 5112 5113static bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) { 5114 bool skipCall = false; 5115 // Validate that cmd buffers have been updated 5116 if (CB_RECORDED != pCB->state) { 5117 if (CB_INVALID == pCB->state) { 5118 // Inform app of reason CB invalid 5119 bool causeReported = false; 5120 if (!pCB->destroyedSets.empty()) { 5121 std::stringstream set_string; 5122 for (auto set : pCB->destroyedSets) 5123 set_string << " " << set; 5124 5125 skipCall |= 5126 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 5127 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 5128 "You are submitting command buffer %#" PRIxLEAST64 5129 " that is invalid because it had the following bound descriptor set(s) destroyed: %s", 5130 (uint64_t)(pCB->commandBuffer), set_string.str().c_str()); 5131 causeReported = true; 5132 } 5133 if (!pCB->updatedSets.empty()) { 5134 std::stringstream set_string; 5135 for (auto set : pCB->updatedSets) 5136 set_string << " " << set; 5137 5138 skipCall |= 5139 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 5140 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 5141 "You are submitting command buffer %#" PRIxLEAST64 5142 " that is invalid because it had the following bound descriptor set(s) updated: %s", 5143 (uint64_t)(pCB->commandBuffer), set_string.str().c_str()); 5144 causeReported = true; 5145 } 5146 if (!pCB->destroyedFramebuffers.empty()) { 5147 std::stringstream fb_string; 5148 for (auto fb : pCB->destroyedFramebuffers) 5149 fb_string << " " << fb; 5150 5151 skipCall |= 5152 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 5153 reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 5154 "You are submitting command buffer %#" PRIxLEAST64 " that is invalid because it had the following " 5155 "referenced framebuffers destroyed: %s", 5156 reinterpret_cast<uint64_t &>(pCB->commandBuffer), fb_string.str().c_str()); 5157 causeReported = true; 5158 } 5159 // TODO : This is defensive programming to make sure an error is 5160 // flagged if we hit this INVALID cmd buffer case and none of the 5161 // above cases are hit. As the number of INVALID cases grows, this 5162 // code should be updated to seemlessly handle all the cases. 5163 if (!causeReported) { 5164 skipCall |= log_msg( 5165 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 5166 reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 5167 "You are submitting command buffer %#" PRIxLEAST64 " that is invalid due to an unknown cause. Validation " 5168 "should " 5169 "be improved to report the exact cause.", 5170 reinterpret_cast<uint64_t &>(pCB->commandBuffer)); 5171 } 5172 } else { // Flag error for using CB w/o vkEndCommandBuffer() called 5173 skipCall |= 5174 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 5175 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS", 5176 "You must call vkEndCommandBuffer() on CB %#" PRIxLEAST64 " before this call to vkQueueSubmit()!", 5177 (uint64_t)(pCB->commandBuffer)); 5178 } 5179 } 5180 return skipCall; 5181} 5182 5183static VkBool32 validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) { 5184 // Track in-use for resources off of primary and any secondary CBs 5185 VkBool32 skipCall = validateAndIncrementResources(dev_data, pCB); 5186 if (!pCB->secondaryCommandBuffers.empty()) { 5187 for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) { 5188 skipCall |= validateAndIncrementResources(dev_data, dev_data->commandBufferMap[secondaryCmdBuffer]); 5189 GLOBAL_CB_NODE *pSubCB = getCBNode(dev_data, secondaryCmdBuffer); 5190 if (pSubCB->primaryCommandBuffer != pCB->commandBuffer) { 5191 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 5192 __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS", 5193 "CB %#" PRIxLEAST64 " was submitted with secondary buffer %#" PRIxLEAST64 5194 " but that buffer has subsequently been bound to " 5195 "primary cmd buffer %#" PRIxLEAST64 ".", 5196 reinterpret_cast<uint64_t>(pCB->commandBuffer), reinterpret_cast<uint64_t>(secondaryCmdBuffer), 5197 reinterpret_cast<uint64_t>(pSubCB->primaryCommandBuffer)); 5198 } 5199 } 5200 } 5201 // TODO : Verify if this also needs to be checked for secondary command 5202 // buffers. If so, this block of code can move to 5203 // validateCommandBufferState() function. vulkan GL106 filed to clarify 5204 if ((pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) && (pCB->submitCount > 1)) { 5205 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 5206 __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS", 5207 "CB %#" PRIxLEAST64 " was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT " 5208 "set, but has been submitted %#" PRIxLEAST64 " times.", 5209 (uint64_t)(pCB->commandBuffer), pCB->submitCount); 5210 } 5211 skipCall |= validateCommandBufferState(dev_data, pCB); 5212 // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing 5213 // on device 5214 skipCall |= validateCommandBufferSimultaneousUse(dev_data, pCB); 5215 return skipCall; 5216} 5217 5218VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 5219vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) { 5220 VkBool32 skipCall = VK_FALSE; 5221 GLOBAL_CB_NODE *pCBNode = NULL; 5222 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); 5223 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 5224 loader_platform_thread_lock_mutex(&globalLock); 5225#if MTMERGESOURCE 5226 // TODO : Need to track fence and clear mem references when fence clears 5227 // MTMTODO : Merge this code with code below to avoid duplicating efforts 5228 uint64_t fenceId = 0; 5229 skipCall = add_fence_info(dev_data, fence, queue, &fenceId); 5230 5231 print_mem_list(dev_data, queue); 5232 printCBList(dev_data, queue); 5233 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5234 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5235 for (uint32_t i = 0; i < submit->commandBufferCount; i++) { 5236 pCBNode = getCBNode(dev_data, submit->pCommandBuffers[i]); 5237 if (pCBNode) { 5238 pCBNode->fenceId = fenceId; 5239 pCBNode->lastSubmittedFence = fence; 5240 pCBNode->lastSubmittedQueue = queue; 5241 for (auto &function : pCBNode->validate_functions) { 5242 skipCall |= function(); 5243 } 5244 for (auto &function : pCBNode->eventUpdates) { 5245 skipCall |= static_cast<VkBool32>(function(queue)); 5246 } 5247 } 5248 } 5249 5250 for (uint32_t i = 0; i < submit->waitSemaphoreCount; i++) { 5251 VkSemaphore sem = submit->pWaitSemaphores[i]; 5252 5253 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 5254 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_SIGNALLED) { 5255 skipCall = 5256 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, 5257 (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE", 5258 "vkQueueSubmit: Semaphore must be in signaled state before passing to pWaitSemaphores"); 5259 } 5260 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_WAIT; 5261 } 5262 } 5263 for (uint32_t i = 0; i < submit->signalSemaphoreCount; i++) { 5264 VkSemaphore sem = submit->pSignalSemaphores[i]; 5265 5266 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 5267 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_UNSET) { 5268 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5269 VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, (uint64_t)sem, __LINE__, MEMTRACK_NONE, 5270 "SEMAPHORE", "vkQueueSubmit: Semaphore must not be currently signaled or in a wait state"); 5271 } 5272 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_SIGNALLED; 5273 } 5274 } 5275 } 5276#endif 5277 // First verify that fence is not in use 5278 if ((fence != VK_NULL_HANDLE) && (submitCount != 0) && dev_data->fenceMap[fence].in_use.load()) { 5279 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 5280 (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", 5281 "Fence %#" PRIx64 " is already in use by another submission.", (uint64_t)(fence)); 5282 } 5283 // Now verify each individual submit 5284 std::unordered_set<VkQueue> processed_other_queues; 5285 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5286 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5287 vector<VkSemaphore> semaphoreList; 5288 for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) { 5289 const VkSemaphore &semaphore = submit->pWaitSemaphores[i]; 5290 semaphoreList.push_back(semaphore); 5291 if (dev_data->semaphoreMap[semaphore].signaled) { 5292 dev_data->semaphoreMap[semaphore].signaled = 0; 5293 } else { 5294 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5295 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, 5296 "DS", "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.", 5297 reinterpret_cast<uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore)); 5298 } 5299 const VkQueue &other_queue = dev_data->semaphoreMap[semaphore].queue; 5300 if (other_queue != VK_NULL_HANDLE && !processed_other_queues.count(other_queue)) { 5301 updateTrackedCommandBuffers(dev_data, queue, other_queue, fence); 5302 processed_other_queues.insert(other_queue); 5303 } 5304 } 5305 for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) { 5306 const VkSemaphore &semaphore = submit->pSignalSemaphores[i]; 5307 semaphoreList.push_back(semaphore); 5308 if (dev_data->semaphoreMap[semaphore].signaled) { 5309 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5310 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, 5311 "DS", "Queue %#" PRIx64 " is signaling semaphore %#" PRIx64 5312 " that has already been signaled but not waited on by queue %#" PRIx64 ".", 5313 reinterpret_cast<uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore), 5314 reinterpret_cast<uint64_t &>(dev_data->semaphoreMap[semaphore].queue)); 5315 } else { 5316 dev_data->semaphoreMap[semaphore].signaled = 1; 5317 dev_data->semaphoreMap[semaphore].queue = queue; 5318 } 5319 } 5320 for (uint32_t i = 0; i < submit->commandBufferCount; i++) { 5321 skipCall |= ValidateCmdBufImageLayouts(submit->pCommandBuffers[i]); 5322 pCBNode = getCBNode(dev_data, submit->pCommandBuffers[i]); 5323 pCBNode->semaphores = semaphoreList; 5324 pCBNode->submitCount++; // increment submit count 5325 skipCall |= validatePrimaryCommandBufferState(dev_data, pCBNode); 5326 } 5327 } 5328 // Update cmdBuffer-related data structs and mark fence in-use 5329 trackCommandBuffers(dev_data, queue, submitCount, pSubmits, fence); 5330 loader_platform_thread_unlock_mutex(&globalLock); 5331 if (VK_FALSE == skipCall) 5332 result = dev_data->device_dispatch_table->QueueSubmit(queue, submitCount, pSubmits, fence); 5333#if MTMERGESOURCE 5334 loader_platform_thread_lock_mutex(&globalLock); 5335 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5336 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5337 for (uint32_t i = 0; i < submit->waitSemaphoreCount; i++) { 5338 VkSemaphore sem = submit->pWaitSemaphores[i]; 5339 5340 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 5341 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_UNSET; 5342 } 5343 } 5344 } 5345 loader_platform_thread_unlock_mutex(&globalLock); 5346#endif 5347 return result; 5348} 5349 5350#if MTMERGESOURCE 5351VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, 5352 const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) { 5353 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5354 VkResult result = my_data->device_dispatch_table->AllocateMemory(device, pAllocateInfo, pAllocator, pMemory); 5355 // TODO : Track allocations and overall size here 5356 loader_platform_thread_lock_mutex(&globalLock); 5357 add_mem_obj_info(my_data, device, *pMemory, pAllocateInfo); 5358 print_mem_list(my_data, device); 5359 loader_platform_thread_unlock_mutex(&globalLock); 5360 return result; 5361} 5362 5363VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5364vkFreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) { 5365 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5366 5367 // From spec : A memory object is freed by calling vkFreeMemory() when it is no longer needed. 5368 // Before freeing a memory object, an application must ensure the memory object is no longer 5369 // in use by the device—for example by command buffers queued for execution. The memory need 5370 // not yet be unbound from all images and buffers, but any further use of those images or 5371 // buffers (on host or device) for anything other than destroying those objects will result in 5372 // undefined behavior. 5373 5374 loader_platform_thread_lock_mutex(&globalLock); 5375 freeMemObjInfo(my_data, device, mem, VK_FALSE); 5376 print_mem_list(my_data, device); 5377 printCBList(my_data, device); 5378 loader_platform_thread_unlock_mutex(&globalLock); 5379 my_data->device_dispatch_table->FreeMemory(device, mem, pAllocator); 5380} 5381 5382VkBool32 validateMemRange(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) { 5383 VkBool32 skipCall = VK_FALSE; 5384 5385 if (size == 0) { 5386 // TODO: a size of 0 is not listed as an invalid use in the spec, should it be? 5387 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 5388 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM", 5389 "VkMapMemory: Attempting to map memory range of size zero"); 5390 } 5391 5392 auto mem_element = my_data->memObjMap.find(mem); 5393 if (mem_element != my_data->memObjMap.end()) { 5394 // It is an application error to call VkMapMemory on an object that is already mapped 5395 if (mem_element->second.memRange.size != 0) { 5396 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 5397 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM", 5398 "VkMapMemory: Attempting to map memory on an already-mapped object %#" PRIxLEAST64, (uint64_t)mem); 5399 } 5400 5401 // Validate that offset + size is within object's allocationSize 5402 if (size == VK_WHOLE_SIZE) { 5403 if (offset >= mem_element->second.allocInfo.allocationSize) { 5404 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5405 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, 5406 "MEM", "Mapping Memory from %" PRIu64 " to %" PRIu64 " with total array size %" PRIu64, offset, 5407 mem_element->second.allocInfo.allocationSize, mem_element->second.allocInfo.allocationSize); 5408 } 5409 } else { 5410 if ((offset + size) > mem_element->second.allocInfo.allocationSize) { 5411 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5412 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, 5413 "MEM", "Mapping Memory from %" PRIu64 " to %" PRIu64 " with total array size %" PRIu64, offset, 5414 size + offset, mem_element->second.allocInfo.allocationSize); 5415 } 5416 } 5417 } 5418 return skipCall; 5419} 5420 5421void storeMemRanges(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) { 5422 auto mem_element = my_data->memObjMap.find(mem); 5423 if (mem_element != my_data->memObjMap.end()) { 5424 MemRange new_range; 5425 new_range.offset = offset; 5426 new_range.size = size; 5427 mem_element->second.memRange = new_range; 5428 } 5429} 5430 5431VkBool32 deleteMemRanges(layer_data *my_data, VkDeviceMemory mem) { 5432 VkBool32 skipCall = VK_FALSE; 5433 auto mem_element = my_data->memObjMap.find(mem); 5434 if (mem_element != my_data->memObjMap.end()) { 5435 if (!mem_element->second.memRange.size) { 5436 // Valid Usage: memory must currently be mapped 5437 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 5438 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM", 5439 "Unmapping Memory without memory being mapped: mem obj %#" PRIxLEAST64, (uint64_t)mem); 5440 } 5441 mem_element->second.memRange.size = 0; 5442 if (mem_element->second.pData) { 5443 free(mem_element->second.pData); 5444 mem_element->second.pData = 0; 5445 } 5446 } 5447 return skipCall; 5448} 5449 5450static char NoncoherentMemoryFillValue = 0xb; 5451 5452void initializeAndTrackMemory(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize size, void **ppData) { 5453 auto mem_element = my_data->memObjMap.find(mem); 5454 if (mem_element != my_data->memObjMap.end()) { 5455 mem_element->second.pDriverData = *ppData; 5456 uint32_t index = mem_element->second.allocInfo.memoryTypeIndex; 5457 if (memProps.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { 5458 mem_element->second.pData = 0; 5459 } else { 5460 if (size == VK_WHOLE_SIZE) { 5461 size = mem_element->second.allocInfo.allocationSize; 5462 } 5463 size_t convSize = (size_t)(size); 5464 mem_element->second.pData = malloc(2 * convSize); 5465 memset(mem_element->second.pData, NoncoherentMemoryFillValue, 2 * convSize); 5466 *ppData = static_cast<char *>(mem_element->second.pData) + (convSize / 2); 5467 } 5468 } 5469} 5470#endif 5471// Note: This function assumes that the global lock is held by the calling 5472// thread. 5473VkBool32 cleanInFlightCmdBuffer(layer_data *my_data, VkCommandBuffer cmdBuffer) { 5474 VkBool32 skip_call = VK_FALSE; 5475 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer); 5476 if (pCB) { 5477 for (auto queryEventsPair : pCB->waitedEventsBeforeQueryReset) { 5478 for (auto event : queryEventsPair.second) { 5479 if (my_data->eventMap[event].needsSignaled) { 5480 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5481 VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS", 5482 "Cannot get query results on queryPool %" PRIu64 5483 " with index %d which was guarded by unsignaled event %" PRIu64 ".", 5484 (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event)); 5485 } 5486 } 5487 } 5488 } 5489 return skip_call; 5490} 5491// Remove given cmd_buffer from the global inFlight set. 5492// Also, if given queue is valid, then remove the cmd_buffer from that queues 5493// inFlightCmdBuffer set. Finally, check all other queues and if given cmd_buffer 5494// is still in flight on another queue, add it back into the global set. 5495// Note: This function assumes that the global lock is held by the calling 5496// thread. 5497static inline void removeInFlightCmdBuffer(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkQueue queue) { 5498 // Pull it off of global list initially, but if we find it in any other queue list, add it back in 5499 dev_data->globalInFlightCmdBuffers.erase(cmd_buffer); 5500 if (dev_data->queueMap.find(queue) != dev_data->queueMap.end()) { 5501 dev_data->queueMap[queue].inFlightCmdBuffers.erase(cmd_buffer); 5502 for (auto q : dev_data->queues) { 5503 if ((q != queue) && 5504 (dev_data->queueMap[q].inFlightCmdBuffers.find(cmd_buffer) != dev_data->queueMap[q].inFlightCmdBuffers.end())) { 5505 dev_data->globalInFlightCmdBuffers.insert(cmd_buffer); 5506 break; 5507 } 5508 } 5509 } 5510} 5511#if MTMERGESOURCE 5512static inline bool verifyFenceStatus(VkDevice device, VkFence fence, const char *apiCall) { 5513 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5514 VkBool32 skipCall = false; 5515 auto pFenceInfo = my_data->fenceMap.find(fence); 5516 if (pFenceInfo != my_data->fenceMap.end()) { 5517 if (pFenceInfo->second.firstTimeFlag != VK_TRUE) { 5518 if ((pFenceInfo->second.createInfo.flags & VK_FENCE_CREATE_SIGNALED_BIT) && 5519 pFenceInfo->second.firstTimeFlag != VK_TRUE) { 5520 skipCall |= 5521 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 5522 (uint64_t)fence, __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", 5523 "%s specified fence %#" PRIxLEAST64 " already in SIGNALED state.", apiCall, (uint64_t)fence); 5524 } 5525 if (!pFenceInfo->second.queue && !pFenceInfo->second.swapchain) { // Checking status of unsubmitted fence 5526 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 5527 reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", 5528 "%s called for fence %#" PRIxLEAST64 " which has not been submitted on a Queue or during " 5529 "acquire next image.", 5530 apiCall, reinterpret_cast<uint64_t &>(fence)); 5531 } 5532 } else { 5533 pFenceInfo->second.firstTimeFlag = VK_FALSE; 5534 } 5535 } 5536 return skipCall; 5537} 5538#endif 5539VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 5540vkWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout) { 5541 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5542 VkBool32 skip_call = VK_FALSE; 5543#if MTMERGESOURCE 5544 // Verify fence status of submitted fences 5545 loader_platform_thread_lock_mutex(&globalLock); 5546 for (uint32_t i = 0; i < fenceCount; i++) { 5547 skip_call |= verifyFenceStatus(device, pFences[i], "vkWaitForFences"); 5548 } 5549 loader_platform_thread_unlock_mutex(&globalLock); 5550 if (skip_call) 5551 return VK_ERROR_VALIDATION_FAILED_EXT; 5552#endif 5553 VkResult result = dev_data->device_dispatch_table->WaitForFences(device, fenceCount, pFences, waitAll, timeout); 5554 5555 if (result == VK_SUCCESS) { 5556 loader_platform_thread_lock_mutex(&globalLock); 5557 // When we know that all fences are complete we can clean/remove their CBs 5558 if (waitAll || fenceCount == 1) { 5559 for (uint32_t i = 0; i < fenceCount; ++i) { 5560#if MTMERGESOURCE 5561 update_fence_tracking(dev_data, pFences[i]); 5562#endif 5563 VkQueue fence_queue = dev_data->fenceMap[pFences[i]].queue; 5564 for (auto cmdBuffer : dev_data->fenceMap[pFences[i]].cmdBuffers) { 5565 skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); 5566 removeInFlightCmdBuffer(dev_data, cmdBuffer, fence_queue); 5567 } 5568 } 5569 decrementResources(dev_data, fenceCount, pFences); 5570 } 5571 // NOTE : Alternate case not handled here is when some fences have completed. In 5572 // this case for app to guarantee which fences completed it will have to call 5573 // vkGetFenceStatus() at which point we'll clean/remove their CBs if complete. 5574 loader_platform_thread_unlock_mutex(&globalLock); 5575 } 5576 if (VK_FALSE != skip_call) 5577 return VK_ERROR_VALIDATION_FAILED_EXT; 5578 return result; 5579} 5580 5581VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus(VkDevice device, VkFence fence) { 5582 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5583 bool skipCall = false; 5584 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 5585#if MTMERGESOURCE 5586 loader_platform_thread_lock_mutex(&globalLock); 5587 skipCall = verifyFenceStatus(device, fence, "vkGetFenceStatus"); 5588 loader_platform_thread_unlock_mutex(&globalLock); 5589 if (skipCall) 5590 return result; 5591#endif 5592 result = dev_data->device_dispatch_table->GetFenceStatus(device, fence); 5593 VkBool32 skip_call = VK_FALSE; 5594 loader_platform_thread_lock_mutex(&globalLock); 5595 if (result == VK_SUCCESS) { 5596#if MTMERGESOURCE 5597 update_fence_tracking(dev_data, fence); 5598#endif 5599 auto fence_queue = dev_data->fenceMap[fence].queue; 5600 for (auto cmdBuffer : dev_data->fenceMap[fence].cmdBuffers) { 5601 skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); 5602 removeInFlightCmdBuffer(dev_data, cmdBuffer, fence_queue); 5603 } 5604 decrementResources(dev_data, 1, &fence); 5605 } 5606 loader_platform_thread_unlock_mutex(&globalLock); 5607 if (VK_FALSE != skip_call) 5608 return VK_ERROR_VALIDATION_FAILED_EXT; 5609 return result; 5610} 5611 5612VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5613vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) { 5614 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5615 dev_data->device_dispatch_table->GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue); 5616 loader_platform_thread_lock_mutex(&globalLock); 5617 dev_data->queues.push_back(*pQueue); 5618 QUEUE_NODE *pQNode = &dev_data->queueMap[*pQueue]; 5619 pQNode->device = device; 5620#if MTMERGESOURCE 5621 pQNode->lastRetiredId = 0; 5622 pQNode->lastSubmittedId = 0; 5623#endif 5624 loader_platform_thread_unlock_mutex(&globalLock); 5625} 5626 5627VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle(VkQueue queue) { 5628 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); 5629 decrementResources(dev_data, queue); 5630 VkBool32 skip_call = VK_FALSE; 5631 loader_platform_thread_lock_mutex(&globalLock); 5632 // Iterate over local set since we erase set members as we go in for loop 5633 auto local_cb_set = dev_data->queueMap[queue].inFlightCmdBuffers; 5634 for (auto cmdBuffer : local_cb_set) { 5635 skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); 5636 removeInFlightCmdBuffer(dev_data, cmdBuffer, queue); 5637 } 5638 dev_data->queueMap[queue].inFlightCmdBuffers.clear(); 5639 loader_platform_thread_unlock_mutex(&globalLock); 5640 if (VK_FALSE != skip_call) 5641 return VK_ERROR_VALIDATION_FAILED_EXT; 5642 VkResult result = dev_data->device_dispatch_table->QueueWaitIdle(queue); 5643#if MTMERGESOURCE 5644 if (VK_SUCCESS == result) { 5645 loader_platform_thread_lock_mutex(&globalLock); 5646 retire_queue_fences(dev_data, queue); 5647 loader_platform_thread_unlock_mutex(&globalLock); 5648 } 5649#endif 5650 return result; 5651} 5652 5653VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle(VkDevice device) { 5654 VkBool32 skip_call = VK_FALSE; 5655 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5656 loader_platform_thread_lock_mutex(&globalLock); 5657 for (auto queue : dev_data->queues) { 5658 decrementResources(dev_data, queue); 5659 if (dev_data->queueMap.find(queue) != dev_data->queueMap.end()) { 5660 // Clear all of the queue inFlightCmdBuffers (global set cleared below) 5661 dev_data->queueMap[queue].inFlightCmdBuffers.clear(); 5662 } 5663 } 5664 for (auto cmdBuffer : dev_data->globalInFlightCmdBuffers) { 5665 skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); 5666 } 5667 dev_data->globalInFlightCmdBuffers.clear(); 5668 loader_platform_thread_unlock_mutex(&globalLock); 5669 if (VK_FALSE != skip_call) 5670 return VK_ERROR_VALIDATION_FAILED_EXT; 5671 VkResult result = dev_data->device_dispatch_table->DeviceWaitIdle(device); 5672#if MTMERGESOURCE 5673 if (VK_SUCCESS == result) { 5674 loader_platform_thread_lock_mutex(&globalLock); 5675 retire_device_fences(dev_data, device); 5676 loader_platform_thread_unlock_mutex(&globalLock); 5677 } 5678#endif 5679 return result; 5680} 5681 5682VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) { 5683 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5684 bool skipCall = false; 5685 loader_platform_thread_lock_mutex(&globalLock); 5686 if (dev_data->fenceMap[fence].in_use.load()) { 5687 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 5688 (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", 5689 "Fence %#" PRIx64 " is in use by a command buffer.", (uint64_t)(fence)); 5690 } 5691#if MTMERGESOURCE 5692 delete_fence_info(dev_data, fence); 5693 auto item = dev_data->fenceMap.find(fence); 5694 if (item != dev_data->fenceMap.end()) { 5695 dev_data->fenceMap.erase(item); 5696 } 5697#endif 5698 loader_platform_thread_unlock_mutex(&globalLock); 5699 if (!skipCall) 5700 dev_data->device_dispatch_table->DestroyFence(device, fence, pAllocator); 5701} 5702 5703VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5704vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) { 5705 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5706 dev_data->device_dispatch_table->DestroySemaphore(device, semaphore, pAllocator); 5707 loader_platform_thread_lock_mutex(&globalLock); 5708 auto item = dev_data->semaphoreMap.find(semaphore); 5709 if (item != dev_data->semaphoreMap.end()) { 5710 if (item->second.in_use.load()) { 5711 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, 5712 reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS", 5713 "Cannot delete semaphore %" PRIx64 " which is in use.", reinterpret_cast<uint64_t &>(semaphore)); 5714 } 5715 dev_data->semaphoreMap.erase(semaphore); 5716 } 5717 loader_platform_thread_unlock_mutex(&globalLock); 5718 // TODO : Clean up any internal data structures using this obj. 5719} 5720 5721VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) { 5722 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5723 bool skip_call = false; 5724 loader_platform_thread_lock_mutex(&globalLock); 5725 auto event_data = dev_data->eventMap.find(event); 5726 if (event_data != dev_data->eventMap.end()) { 5727 if (event_data->second.in_use.load()) { 5728 skip_call |= log_msg( 5729 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 5730 reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS", 5731 "Cannot delete event %" PRIx64 " which is in use by a command buffer.", reinterpret_cast<uint64_t &>(event)); 5732 } 5733 dev_data->eventMap.erase(event_data); 5734 } 5735 loader_platform_thread_unlock_mutex(&globalLock); 5736 if (!skip_call) 5737 dev_data->device_dispatch_table->DestroyEvent(device, event, pAllocator); 5738 // TODO : Clean up any internal data structures using this obj. 5739} 5740 5741VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5742vkDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) { 5743 get_my_data_ptr(get_dispatch_key(device), layer_data_map) 5744 ->device_dispatch_table->DestroyQueryPool(device, queryPool, pAllocator); 5745 // TODO : Clean up any internal data structures using this obj. 5746} 5747 5748VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, 5749 uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride, 5750 VkQueryResultFlags flags) { 5751 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5752 unordered_map<QueryObject, vector<VkCommandBuffer>> queriesInFlight; 5753 GLOBAL_CB_NODE *pCB = nullptr; 5754 loader_platform_thread_lock_mutex(&globalLock); 5755 for (auto cmdBuffer : dev_data->globalInFlightCmdBuffers) { 5756 pCB = getCBNode(dev_data, cmdBuffer); 5757 for (auto queryStatePair : pCB->queryToStateMap) { 5758 queriesInFlight[queryStatePair.first].push_back(cmdBuffer); 5759 } 5760 } 5761 VkBool32 skip_call = VK_FALSE; 5762 for (uint32_t i = 0; i < queryCount; ++i) { 5763 QueryObject query = {queryPool, firstQuery + i}; 5764 auto queryElement = queriesInFlight.find(query); 5765 auto queryToStateElement = dev_data->queryToStateMap.find(query); 5766 if (queryToStateElement != dev_data->queryToStateMap.end()) { 5767 } 5768 // Available and in flight 5769 if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() && 5770 queryToStateElement->second) { 5771 for (auto cmdBuffer : queryElement->second) { 5772 pCB = getCBNode(dev_data, cmdBuffer); 5773 auto queryEventElement = pCB->waitedEventsBeforeQueryReset.find(query); 5774 if (queryEventElement == pCB->waitedEventsBeforeQueryReset.end()) { 5775 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5776 VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", 5777 "Cannot get query results on queryPool %" PRIu64 " with index %d which is in flight.", 5778 (uint64_t)(queryPool), firstQuery + i); 5779 } else { 5780 for (auto event : queryEventElement->second) { 5781 dev_data->eventMap[event].needsSignaled = true; 5782 } 5783 } 5784 } 5785 // Unavailable and in flight 5786 } else if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() && 5787 !queryToStateElement->second) { 5788 // TODO : Can there be the same query in use by multiple command buffers in flight? 5789 bool make_available = false; 5790 for (auto cmdBuffer : queryElement->second) { 5791 pCB = getCBNode(dev_data, cmdBuffer); 5792 make_available |= pCB->queryToStateMap[query]; 5793 } 5794 if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) { 5795 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5796 VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", 5797 "Cannot get query results on queryPool %" PRIu64 " with index %d which is unavailable.", 5798 (uint64_t)(queryPool), firstQuery + i); 5799 } 5800 // Unavailable 5801 } else if (queryToStateElement != dev_data->queryToStateMap.end() && !queryToStateElement->second) { 5802 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 5803 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", 5804 "Cannot get query results on queryPool %" PRIu64 " with index %d which is unavailable.", 5805 (uint64_t)(queryPool), firstQuery + i); 5806 // Unitialized 5807 } else if (queryToStateElement == dev_data->queryToStateMap.end()) { 5808 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 5809 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", 5810 "Cannot get query results on queryPool %" PRIu64 " with index %d which is uninitialized.", 5811 (uint64_t)(queryPool), firstQuery + i); 5812 } 5813 } 5814 loader_platform_thread_unlock_mutex(&globalLock); 5815 if (skip_call) 5816 return VK_ERROR_VALIDATION_FAILED_EXT; 5817 return dev_data->device_dispatch_table->GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, 5818 flags); 5819} 5820 5821VkBool32 validateIdleBuffer(const layer_data *my_data, VkBuffer buffer) { 5822 VkBool32 skip_call = VK_FALSE; 5823 auto buffer_data = my_data->bufferMap.find(buffer); 5824 if (buffer_data == my_data->bufferMap.end()) { 5825 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, 5826 (uint64_t)(buffer), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS", 5827 "Cannot free buffer %" PRIxLEAST64 " that has not been allocated.", (uint64_t)(buffer)); 5828 } else { 5829 if (buffer_data->second.in_use.load()) { 5830 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, 5831 (uint64_t)(buffer), __LINE__, DRAWSTATE_OBJECT_INUSE, "DS", 5832 "Cannot free buffer %" PRIxLEAST64 " that is in use by a command buffer.", (uint64_t)(buffer)); 5833 } 5834 } 5835 return skip_call; 5836} 5837 5838VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5839vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) { 5840 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5841 VkBool32 skipCall = VK_FALSE; 5842 loader_platform_thread_lock_mutex(&globalLock); 5843#if MTMERGESOURCE 5844 auto item = dev_data->bufferBindingMap.find((uint64_t)buffer); 5845 if (item != dev_data->bufferBindingMap.end()) { 5846 skipCall = clear_object_binding(dev_data, device, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT); 5847 dev_data->bufferBindingMap.erase(item); 5848 } 5849#endif 5850 if (!validateIdleBuffer(dev_data, buffer) && (VK_FALSE == skipCall)) { 5851 loader_platform_thread_unlock_mutex(&globalLock); 5852 dev_data->device_dispatch_table->DestroyBuffer(device, buffer, pAllocator); 5853 loader_platform_thread_lock_mutex(&globalLock); 5854 } 5855 dev_data->bufferMap.erase(buffer); 5856 loader_platform_thread_unlock_mutex(&globalLock); 5857} 5858 5859VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5860vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) { 5861 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5862 dev_data->device_dispatch_table->DestroyBufferView(device, bufferView, pAllocator); 5863 loader_platform_thread_lock_mutex(&globalLock); 5864 auto item = dev_data->bufferViewMap.find(bufferView); 5865 if (item != dev_data->bufferViewMap.end()) { 5866 dev_data->bufferViewMap.erase(item); 5867 } 5868 loader_platform_thread_unlock_mutex(&globalLock); 5869} 5870 5871VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) { 5872 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5873 VkBool32 skipCall = VK_FALSE; 5874#if MTMERGESOURCE 5875 loader_platform_thread_lock_mutex(&globalLock); 5876 auto item = dev_data->imageBindingMap.find((uint64_t)image); 5877 if (item != dev_data->imageBindingMap.end()) { 5878 skipCall = clear_object_binding(dev_data, device, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); 5879 dev_data->imageBindingMap.erase(item); 5880 } 5881 loader_platform_thread_unlock_mutex(&globalLock); 5882#endif 5883 if (VK_FALSE == skipCall) 5884 dev_data->device_dispatch_table->DestroyImage(device, image, pAllocator); 5885 5886 loader_platform_thread_lock_mutex(&globalLock); 5887 const auto& entry = dev_data->imageMap.find(image); 5888 if (entry != dev_data->imageMap.end()) { 5889 // Clear any memory mapping for this image 5890 const auto &mem_entry = dev_data->memObjMap.find(entry->second.mem); 5891 if (mem_entry != dev_data->memObjMap.end()) 5892 mem_entry->second.image = VK_NULL_HANDLE; 5893 5894 // Remove image from imageMap 5895 dev_data->imageMap.erase(entry); 5896 } 5897 const auto& subEntry = dev_data->imageSubresourceMap.find(image); 5898 if (subEntry != dev_data->imageSubresourceMap.end()) { 5899 for (const auto& pair : subEntry->second) { 5900 dev_data->imageLayoutMap.erase(pair); 5901 } 5902 dev_data->imageSubresourceMap.erase(subEntry); 5903 } 5904 loader_platform_thread_unlock_mutex(&globalLock); 5905} 5906#if MTMERGESOURCE 5907VkBool32 print_memory_range_error(layer_data *dev_data, const uint64_t object_handle, const uint64_t other_handle, 5908 VkDebugReportObjectTypeEXT object_type) { 5909 if (object_type == VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT) { 5910 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0, 5911 MEMTRACK_INVALID_ALIASING, "MEM", "Buffer %" PRIx64 " is alised with image %" PRIx64, object_handle, 5912 other_handle); 5913 } else { 5914 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0, 5915 MEMTRACK_INVALID_ALIASING, "MEM", "Image %" PRIx64 " is alised with buffer %" PRIx64, object_handle, 5916 other_handle); 5917 } 5918} 5919 5920VkBool32 validate_memory_range(layer_data *dev_data, const vector<MEMORY_RANGE> &ranges, const MEMORY_RANGE &new_range, 5921 VkDebugReportObjectTypeEXT object_type) { 5922 VkBool32 skip_call = false; 5923 5924 for (auto range : ranges) { 5925 if ((range.end & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1)) < 5926 (new_range.start & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1))) 5927 continue; 5928 if ((range.start & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1)) > 5929 (new_range.end & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1))) 5930 continue; 5931 skip_call |= print_memory_range_error(dev_data, new_range.handle, range.handle, object_type); 5932 } 5933 return skip_call; 5934} 5935 5936VkBool32 validate_buffer_image_aliasing(layer_data *dev_data, uint64_t handle, VkDeviceMemory mem, VkDeviceSize memoryOffset, 5937 VkMemoryRequirements memRequirements, vector<MEMORY_RANGE> &ranges, 5938 const vector<MEMORY_RANGE> &other_ranges, VkDebugReportObjectTypeEXT object_type) { 5939 MEMORY_RANGE range; 5940 range.handle = handle; 5941 range.memory = mem; 5942 range.start = memoryOffset; 5943 range.end = memoryOffset + memRequirements.size - 1; 5944 ranges.push_back(range); 5945 return validate_memory_range(dev_data, other_ranges, range, object_type); 5946} 5947 5948VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 5949vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) { 5950 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5951 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 5952 loader_platform_thread_lock_mutex(&globalLock); 5953 // Track objects tied to memory 5954 uint64_t buffer_handle = (uint64_t)(buffer); 5955 VkBool32 skipCall = 5956 set_mem_binding(dev_data, device, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory"); 5957 add_object_binding_info(dev_data, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, mem); 5958 { 5959 VkMemoryRequirements memRequirements; 5960 // MTMTODO : Shouldn't this call down the chain? 5961 vkGetBufferMemoryRequirements(device, buffer, &memRequirements); 5962 skipCall |= validate_buffer_image_aliasing(dev_data, buffer_handle, mem, memoryOffset, memRequirements, 5963 dev_data->memObjMap[mem].bufferRanges, dev_data->memObjMap[mem].imageRanges, 5964 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT); 5965 } 5966 print_mem_list(dev_data, device); 5967 loader_platform_thread_unlock_mutex(&globalLock); 5968 if (VK_FALSE == skipCall) { 5969 result = dev_data->device_dispatch_table->BindBufferMemory(device, buffer, mem, memoryOffset); 5970 } 5971 return result; 5972} 5973 5974VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5975vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) { 5976 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5977 // TODO : What to track here? 5978 // Could potentially save returned mem requirements and validate values passed into BindBufferMemory 5979 my_data->device_dispatch_table->GetBufferMemoryRequirements(device, buffer, pMemoryRequirements); 5980} 5981 5982VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5983vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) { 5984 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5985 // TODO : What to track here? 5986 // Could potentially save returned mem requirements and validate values passed into BindImageMemory 5987 my_data->device_dispatch_table->GetImageMemoryRequirements(device, image, pMemoryRequirements); 5988} 5989#endif 5990VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5991vkDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) { 5992 get_my_data_ptr(get_dispatch_key(device), layer_data_map) 5993 ->device_dispatch_table->DestroyImageView(device, imageView, pAllocator); 5994 // TODO : Clean up any internal data structures using this obj. 5995} 5996 5997VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5998vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator) { 5999 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6000 6001 loader_platform_thread_lock_mutex(&globalLock); 6002 6003 my_data->shaderModuleMap.erase(shaderModule); 6004 6005 loader_platform_thread_unlock_mutex(&globalLock); 6006 6007 my_data->device_dispatch_table->DestroyShaderModule(device, shaderModule, pAllocator); 6008} 6009 6010VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6011vkDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) { 6012 get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroyPipeline(device, pipeline, pAllocator); 6013 // TODO : Clean up any internal data structures using this obj. 6014} 6015 6016VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6017vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator) { 6018 get_my_data_ptr(get_dispatch_key(device), layer_data_map) 6019 ->device_dispatch_table->DestroyPipelineLayout(device, pipelineLayout, pAllocator); 6020 // TODO : Clean up any internal data structures using this obj. 6021} 6022 6023VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6024vkDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) { 6025 get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroySampler(device, sampler, pAllocator); 6026 // TODO : Clean up any internal data structures using this obj. 6027} 6028 6029VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6030vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator) { 6031 get_my_data_ptr(get_dispatch_key(device), layer_data_map) 6032 ->device_dispatch_table->DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator); 6033 // TODO : Clean up any internal data structures using this obj. 6034} 6035 6036VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6037vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) { 6038 get_my_data_ptr(get_dispatch_key(device), layer_data_map) 6039 ->device_dispatch_table->DestroyDescriptorPool(device, descriptorPool, pAllocator); 6040 // TODO : Clean up any internal data structures using this obj. 6041} 6042 6043VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6044vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) { 6045 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6046 6047 bool skip_call = false; 6048 loader_platform_thread_lock_mutex(&globalLock); 6049 for (uint32_t i = 0; i < commandBufferCount; i++) { 6050#if MTMERGESOURCE 6051 clear_cmd_buf_and_mem_references(dev_data, pCommandBuffers[i]); 6052#endif 6053 if (dev_data->globalInFlightCmdBuffers.count(pCommandBuffers[i])) { 6054 skip_call |= 6055 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6056 reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", 6057 "Attempt to free command buffer (%#" PRIxLEAST64 ") which is in use.", 6058 reinterpret_cast<uint64_t>(pCommandBuffers[i])); 6059 } 6060 // Delete CB information structure, and remove from commandBufferMap 6061 auto cb = dev_data->commandBufferMap.find(pCommandBuffers[i]); 6062 if (cb != dev_data->commandBufferMap.end()) { 6063 // reset prior to delete for data clean-up 6064 resetCB(dev_data, (*cb).second->commandBuffer); 6065 delete (*cb).second; 6066 dev_data->commandBufferMap.erase(cb); 6067 } 6068 6069 // Remove commandBuffer reference from commandPoolMap 6070 dev_data->commandPoolMap[commandPool].commandBuffers.remove(pCommandBuffers[i]); 6071 } 6072#if MTMERGESOURCE 6073 printCBList(dev_data, device); 6074#endif 6075 loader_platform_thread_unlock_mutex(&globalLock); 6076 6077 if (!skip_call) 6078 dev_data->device_dispatch_table->FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers); 6079} 6080 6081VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo, 6082 const VkAllocationCallbacks *pAllocator, 6083 VkCommandPool *pCommandPool) { 6084 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6085 6086 VkResult result = dev_data->device_dispatch_table->CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool); 6087 6088 if (VK_SUCCESS == result) { 6089 loader_platform_thread_lock_mutex(&globalLock); 6090 dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags; 6091 dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex; 6092 loader_platform_thread_unlock_mutex(&globalLock); 6093 } 6094 return result; 6095} 6096 6097VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo, 6098 const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) { 6099 6100 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6101 VkResult result = dev_data->device_dispatch_table->CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool); 6102 if (result == VK_SUCCESS) { 6103 loader_platform_thread_lock_mutex(&globalLock); 6104 dev_data->queryPoolMap[*pQueryPool].createInfo = *pCreateInfo; 6105 loader_platform_thread_unlock_mutex(&globalLock); 6106 } 6107 return result; 6108} 6109 6110VkBool32 validateCommandBuffersNotInUse(const layer_data *dev_data, VkCommandPool commandPool) { 6111 VkBool32 skipCall = VK_FALSE; 6112 auto pool_data = dev_data->commandPoolMap.find(commandPool); 6113 if (pool_data != dev_data->commandPoolMap.end()) { 6114 for (auto cmdBuffer : pool_data->second.commandBuffers) { 6115 if (dev_data->globalInFlightCmdBuffers.count(cmdBuffer)) { 6116 skipCall |= 6117 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT, 6118 (uint64_t)(commandPool), __LINE__, DRAWSTATE_OBJECT_INUSE, "DS", 6119 "Cannot reset command pool %" PRIx64 " when allocated command buffer %" PRIx64 " is in use.", 6120 (uint64_t)(commandPool), (uint64_t)(cmdBuffer)); 6121 } 6122 } 6123 } 6124 return skipCall; 6125} 6126 6127// Destroy commandPool along with all of the commandBuffers allocated from that pool 6128VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6129vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) { 6130 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6131 bool commandBufferComplete = false; 6132 bool skipCall = false; 6133 loader_platform_thread_lock_mutex(&globalLock); 6134#if MTMERGESOURCE 6135 // Verify that command buffers in pool are complete (not in-flight) 6136 // MTMTODO : Merge this with code below (separate *NotInUse() call) 6137 for (auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); 6138 it != dev_data->commandPoolMap[commandPool].commandBuffers.end(); it++) { 6139 commandBufferComplete = VK_FALSE; 6140 skipCall = checkCBCompleted(dev_data, *it, &commandBufferComplete); 6141 if (VK_FALSE == commandBufferComplete) { 6142 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6143 (uint64_t)(*it), __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", 6144 "Destroying Command Pool 0x%" PRIxLEAST64 " before " 6145 "its command buffer (0x%" PRIxLEAST64 ") has completed.", 6146 (uint64_t)(commandPool), reinterpret_cast<uint64_t>(*it)); 6147 } 6148 } 6149#endif 6150 // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandPoolMap 6151 if (dev_data->commandPoolMap.find(commandPool) != dev_data->commandPoolMap.end()) { 6152 for (auto poolCb = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); 6153 poolCb != dev_data->commandPoolMap[commandPool].commandBuffers.end();) { 6154 auto del_cb = dev_data->commandBufferMap.find(*poolCb); 6155 delete (*del_cb).second; // delete CB info structure 6156 dev_data->commandBufferMap.erase(del_cb); // Remove this command buffer 6157 poolCb = dev_data->commandPoolMap[commandPool].commandBuffers.erase( 6158 poolCb); // Remove CB reference from commandPoolMap's list 6159 } 6160 } 6161 dev_data->commandPoolMap.erase(commandPool); 6162 6163 loader_platform_thread_unlock_mutex(&globalLock); 6164 6165 if (VK_TRUE == validateCommandBuffersNotInUse(dev_data, commandPool)) 6166 return; 6167 6168 if (!skipCall) 6169 dev_data->device_dispatch_table->DestroyCommandPool(device, commandPool, pAllocator); 6170#if MTMERGESOURCE 6171 loader_platform_thread_lock_mutex(&globalLock); 6172 auto item = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); 6173 // Remove command buffers from command buffer map 6174 while (item != dev_data->commandPoolMap[commandPool].commandBuffers.end()) { 6175 auto del_item = item++; 6176 delete_cmd_buf_info(dev_data, commandPool, *del_item); 6177 } 6178 dev_data->commandPoolMap.erase(commandPool); 6179 loader_platform_thread_unlock_mutex(&globalLock); 6180#endif 6181} 6182 6183VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6184vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) { 6185 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6186 bool commandBufferComplete = false; 6187 bool skipCall = false; 6188 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 6189#if MTMERGESOURCE 6190 // MTMTODO : Merge this with *NotInUse() call below 6191 loader_platform_thread_lock_mutex(&globalLock); 6192 auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); 6193 // Verify that CB's in pool are complete (not in-flight) 6194 while (it != dev_data->commandPoolMap[commandPool].commandBuffers.end()) { 6195 skipCall = checkCBCompleted(dev_data, (*it), &commandBufferComplete); 6196 if (!commandBufferComplete) { 6197 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6198 (uint64_t)(*it), __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", 6199 "Resetting CB %p before it has completed. You must check CB " 6200 "flag before calling vkResetCommandBuffer().", 6201 (*it)); 6202 } else { 6203 // Clear memory references at this point. 6204 clear_cmd_buf_and_mem_references(dev_data, (*it)); 6205 } 6206 ++it; 6207 } 6208 loader_platform_thread_unlock_mutex(&globalLock); 6209#endif 6210 if (VK_TRUE == validateCommandBuffersNotInUse(dev_data, commandPool)) 6211 return VK_ERROR_VALIDATION_FAILED_EXT; 6212 6213 if (!skipCall) 6214 result = dev_data->device_dispatch_table->ResetCommandPool(device, commandPool, flags); 6215 6216 // Reset all of the CBs allocated from this pool 6217 if (VK_SUCCESS == result) { 6218 loader_platform_thread_lock_mutex(&globalLock); 6219 auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); 6220 while (it != dev_data->commandPoolMap[commandPool].commandBuffers.end()) { 6221 resetCB(dev_data, (*it)); 6222 ++it; 6223 } 6224 loader_platform_thread_unlock_mutex(&globalLock); 6225 } 6226 return result; 6227} 6228 6229VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) { 6230 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6231 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 6232 bool skipCall = false; 6233 loader_platform_thread_lock_mutex(&globalLock); 6234 for (uint32_t i = 0; i < fenceCount; ++i) { 6235#if MTMERGESOURCE 6236 // Reset fence state in fenceCreateInfo structure 6237 // MTMTODO : Merge with code below 6238 auto fence_item = dev_data->fenceMap.find(pFences[i]); 6239 if (fence_item != dev_data->fenceMap.end()) { 6240 // Validate fences in SIGNALED state 6241 if (!(fence_item->second.createInfo.flags & VK_FENCE_CREATE_SIGNALED_BIT)) { 6242 // TODO: I don't see a Valid Usage section for ResetFences. This behavior should be documented there. 6243 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 6244 (uint64_t)pFences[i], __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", 6245 "Fence %#" PRIxLEAST64 " submitted to VkResetFences in UNSIGNALED STATE", (uint64_t)pFences[i]); 6246 } else { 6247 fence_item->second.createInfo.flags = 6248 static_cast<VkFenceCreateFlags>(fence_item->second.createInfo.flags & ~VK_FENCE_CREATE_SIGNALED_BIT); 6249 } 6250 } 6251#endif 6252 if (dev_data->fenceMap[pFences[i]].in_use.load()) { 6253 skipCall |= 6254 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 6255 reinterpret_cast<const uint64_t &>(pFences[i]), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", 6256 "Fence %#" PRIx64 " is in use by a command buffer.", reinterpret_cast<const uint64_t &>(pFences[i])); 6257 } 6258 } 6259 loader_platform_thread_unlock_mutex(&globalLock); 6260 if (!skipCall) 6261 result = dev_data->device_dispatch_table->ResetFences(device, fenceCount, pFences); 6262 return result; 6263} 6264 6265VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6266vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) { 6267 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6268 auto fbNode = dev_data->frameBufferMap.find(framebuffer); 6269 if (fbNode != dev_data->frameBufferMap.end()) { 6270 for (auto cb : fbNode->second.referencingCmdBuffers) { 6271 auto cbNode = dev_data->commandBufferMap.find(cb); 6272 if (cbNode != dev_data->commandBufferMap.end()) { 6273 // Set CB as invalid and record destroyed framebuffer 6274 cbNode->second->state = CB_INVALID; 6275 loader_platform_thread_lock_mutex(&globalLock); 6276 cbNode->second->destroyedFramebuffers.insert(framebuffer); 6277 loader_platform_thread_unlock_mutex(&globalLock); 6278 } 6279 } 6280 loader_platform_thread_lock_mutex(&globalLock); 6281 dev_data->frameBufferMap.erase(framebuffer); 6282 loader_platform_thread_unlock_mutex(&globalLock); 6283 } 6284 dev_data->device_dispatch_table->DestroyFramebuffer(device, framebuffer, pAllocator); 6285} 6286 6287VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6288vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) { 6289 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6290 dev_data->device_dispatch_table->DestroyRenderPass(device, renderPass, pAllocator); 6291 loader_platform_thread_lock_mutex(&globalLock); 6292 dev_data->renderPassMap.erase(renderPass); 6293 loader_platform_thread_unlock_mutex(&globalLock); 6294} 6295 6296VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, 6297 const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) { 6298 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6299 6300 VkResult result = dev_data->device_dispatch_table->CreateBuffer(device, pCreateInfo, pAllocator, pBuffer); 6301 6302 if (VK_SUCCESS == result) { 6303 loader_platform_thread_lock_mutex(&globalLock); 6304#if MTMERGESOURCE 6305 add_object_create_info(dev_data, (uint64_t)*pBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, pCreateInfo); 6306#endif 6307 // TODO : This doesn't create deep copy of pQueueFamilyIndices so need to fix that if/when we want that data to be valid 6308 dev_data->bufferMap[*pBuffer].create_info = unique_ptr<VkBufferCreateInfo>(new VkBufferCreateInfo(*pCreateInfo)); 6309 dev_data->bufferMap[*pBuffer].in_use.store(0); 6310 loader_platform_thread_unlock_mutex(&globalLock); 6311 } 6312 return result; 6313} 6314 6315VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo, 6316 const VkAllocationCallbacks *pAllocator, VkBufferView *pView) { 6317 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6318 VkResult result = dev_data->device_dispatch_table->CreateBufferView(device, pCreateInfo, pAllocator, pView); 6319 if (VK_SUCCESS == result) { 6320 loader_platform_thread_lock_mutex(&globalLock); 6321 dev_data->bufferViewMap[*pView] = VkBufferViewCreateInfo(*pCreateInfo); 6322#if MTMERGESOURCE 6323 // In order to create a valid buffer view, the buffer must have been created with at least one of the 6324 // following flags: UNIFORM_TEXEL_BUFFER_BIT or STORAGE_TEXEL_BUFFER_BIT 6325 validate_buffer_usage_flags(dev_data, device, pCreateInfo->buffer, 6326 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, VK_FALSE, 6327 "vkCreateBufferView()", "VK_BUFFER_USAGE_[STORAGE|UNIFORM]_TEXEL_BUFFER_BIT"); 6328#endif 6329 loader_platform_thread_unlock_mutex(&globalLock); 6330 } 6331 return result; 6332} 6333 6334VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, 6335 const VkAllocationCallbacks *pAllocator, VkImage *pImage) { 6336 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6337 6338 VkResult result = dev_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage); 6339 6340 if (VK_SUCCESS == result) { 6341 loader_platform_thread_lock_mutex(&globalLock); 6342#if MTMERGESOURCE 6343 add_object_create_info(dev_data, (uint64_t)*pImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, pCreateInfo); 6344#endif 6345 IMAGE_LAYOUT_NODE image_node; 6346 image_node.layout = pCreateInfo->initialLayout; 6347 image_node.format = pCreateInfo->format; 6348 dev_data->imageMap[*pImage].createInfo = *pCreateInfo; 6349 ImageSubresourcePair subpair = {*pImage, false, VkImageSubresource()}; 6350 dev_data->imageSubresourceMap[*pImage].push_back(subpair); 6351 dev_data->imageLayoutMap[subpair] = image_node; 6352 loader_platform_thread_unlock_mutex(&globalLock); 6353 } 6354 return result; 6355} 6356 6357static void ResolveRemainingLevelsLayers(layer_data *dev_data, VkImageSubresourceRange *range, VkImage image) { 6358 /* expects globalLock to be held by caller */ 6359 6360 auto image_node_it = dev_data->imageMap.find(image); 6361 if (image_node_it != dev_data->imageMap.end()) { 6362 /* If the caller used the special values VK_REMAINING_MIP_LEVELS and 6363 * VK_REMAINING_ARRAY_LAYERS, resolve them now in our internal state to 6364 * the actual values. 6365 */ 6366 if (range->levelCount == VK_REMAINING_MIP_LEVELS) { 6367 range->levelCount = image_node_it->second.createInfo.mipLevels - range->baseMipLevel; 6368 } 6369 6370 if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) { 6371 range->layerCount = image_node_it->second.createInfo.arrayLayers - range->baseArrayLayer; 6372 } 6373 } 6374} 6375 6376// Return the correct layer/level counts if the caller used the special 6377// values VK_REMAINING_MIP_LEVELS or VK_REMAINING_ARRAY_LAYERS. 6378static void ResolveRemainingLevelsLayers(layer_data *dev_data, uint32_t *levels, uint32_t *layers, VkImageSubresourceRange range, 6379 VkImage image) { 6380 /* expects globalLock to be held by caller */ 6381 6382 *levels = range.levelCount; 6383 *layers = range.layerCount; 6384 auto image_node_it = dev_data->imageMap.find(image); 6385 if (image_node_it != dev_data->imageMap.end()) { 6386 if (range.levelCount == VK_REMAINING_MIP_LEVELS) { 6387 *levels = image_node_it->second.createInfo.mipLevels - range.baseMipLevel; 6388 } 6389 if (range.layerCount == VK_REMAINING_ARRAY_LAYERS) { 6390 *layers = image_node_it->second.createInfo.arrayLayers - range.baseArrayLayer; 6391 } 6392 } 6393} 6394 6395VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo, 6396 const VkAllocationCallbacks *pAllocator, VkImageView *pView) { 6397 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6398 VkResult result = dev_data->device_dispatch_table->CreateImageView(device, pCreateInfo, pAllocator, pView); 6399 if (VK_SUCCESS == result) { 6400 loader_platform_thread_lock_mutex(&globalLock); 6401 VkImageViewCreateInfo localCI = VkImageViewCreateInfo(*pCreateInfo); 6402 ResolveRemainingLevelsLayers(dev_data, &localCI.subresourceRange, pCreateInfo->image); 6403 dev_data->imageViewMap[*pView] = localCI; 6404#if MTMERGESOURCE 6405 // Validate that img has correct usage flags set 6406 validate_image_usage_flags(dev_data, device, pCreateInfo->image, 6407 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | 6408 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 6409 VK_FALSE, "vkCreateImageView()", "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT]_BIT"); 6410#endif 6411 loader_platform_thread_unlock_mutex(&globalLock); 6412 } 6413 return result; 6414} 6415 6416VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6417vkCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence) { 6418 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6419 VkResult result = dev_data->device_dispatch_table->CreateFence(device, pCreateInfo, pAllocator, pFence); 6420 if (VK_SUCCESS == result) { 6421 loader_platform_thread_lock_mutex(&globalLock); 6422 FENCE_NODE *pFN = &dev_data->fenceMap[*pFence]; 6423#if MTMERGESOURCE 6424 memset(pFN, 0, sizeof(MT_FENCE_INFO)); 6425 memcpy(&(pFN->createInfo), pCreateInfo, sizeof(VkFenceCreateInfo)); 6426 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) { 6427 pFN->firstTimeFlag = VK_TRUE; 6428 } 6429#endif 6430 pFN->in_use.store(0); 6431 loader_platform_thread_unlock_mutex(&globalLock); 6432 } 6433 return result; 6434} 6435 6436// TODO handle pipeline caches 6437VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo, 6438 const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) { 6439 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6440 VkResult result = dev_data->device_dispatch_table->CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache); 6441 return result; 6442} 6443 6444VKAPI_ATTR void VKAPI_CALL 6445vkDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks *pAllocator) { 6446 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6447 dev_data->device_dispatch_table->DestroyPipelineCache(device, pipelineCache, pAllocator); 6448} 6449 6450VKAPI_ATTR VkResult VKAPI_CALL 6451vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize, void *pData) { 6452 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6453 VkResult result = dev_data->device_dispatch_table->GetPipelineCacheData(device, pipelineCache, pDataSize, pData); 6454 return result; 6455} 6456 6457VKAPI_ATTR VkResult VKAPI_CALL 6458vkMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches) { 6459 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6460 VkResult result = dev_data->device_dispatch_table->MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches); 6461 return result; 6462} 6463 6464VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6465vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count, 6466 const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, 6467 VkPipeline *pPipelines) { 6468 VkResult result = VK_SUCCESS; 6469 // TODO What to do with pipelineCache? 6470 // The order of operations here is a little convoluted but gets the job done 6471 // 1. Pipeline create state is first shadowed into PIPELINE_NODE struct 6472 // 2. Create state is then validated (which uses flags setup during shadowing) 6473 // 3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap 6474 VkBool32 skipCall = VK_FALSE; 6475 // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic 6476 vector<PIPELINE_NODE *> pPipeNode(count); 6477 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6478 6479 uint32_t i = 0; 6480 loader_platform_thread_lock_mutex(&globalLock); 6481 6482 for (i = 0; i < count; i++) { 6483 pPipeNode[i] = initGraphicsPipeline(dev_data, &pCreateInfos[i]); 6484 skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode, i); 6485 } 6486 6487 if (VK_FALSE == skipCall) { 6488 loader_platform_thread_unlock_mutex(&globalLock); 6489 result = dev_data->device_dispatch_table->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, 6490 pPipelines); 6491 loader_platform_thread_lock_mutex(&globalLock); 6492 for (i = 0; i < count; i++) { 6493 pPipeNode[i]->pipeline = pPipelines[i]; 6494 dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i]; 6495 } 6496 loader_platform_thread_unlock_mutex(&globalLock); 6497 } else { 6498 for (i = 0; i < count; i++) { 6499 delete pPipeNode[i]; 6500 } 6501 loader_platform_thread_unlock_mutex(&globalLock); 6502 return VK_ERROR_VALIDATION_FAILED_EXT; 6503 } 6504 return result; 6505} 6506 6507VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6508vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count, 6509 const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, 6510 VkPipeline *pPipelines) { 6511 VkResult result = VK_SUCCESS; 6512 VkBool32 skipCall = VK_FALSE; 6513 6514 // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic 6515 vector<PIPELINE_NODE *> pPipeNode(count); 6516 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6517 6518 uint32_t i = 0; 6519 loader_platform_thread_lock_mutex(&globalLock); 6520 for (i = 0; i < count; i++) { 6521 // TODO: Verify compute stage bits 6522 6523 // Create and initialize internal tracking data structure 6524 pPipeNode[i] = new PIPELINE_NODE; 6525 memcpy(&pPipeNode[i]->computePipelineCI, (const void *)&pCreateInfos[i], sizeof(VkComputePipelineCreateInfo)); 6526 6527 // TODO: Add Compute Pipeline Verification 6528 // skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode[i]); 6529 } 6530 6531 if (VK_FALSE == skipCall) { 6532 loader_platform_thread_unlock_mutex(&globalLock); 6533 result = dev_data->device_dispatch_table->CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, 6534 pPipelines); 6535 loader_platform_thread_lock_mutex(&globalLock); 6536 for (i = 0; i < count; i++) { 6537 pPipeNode[i]->pipeline = pPipelines[i]; 6538 dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i]; 6539 } 6540 loader_platform_thread_unlock_mutex(&globalLock); 6541 } else { 6542 for (i = 0; i < count; i++) { 6543 // Clean up any locally allocated data structures 6544 delete pPipeNode[i]; 6545 } 6546 loader_platform_thread_unlock_mutex(&globalLock); 6547 return VK_ERROR_VALIDATION_FAILED_EXT; 6548 } 6549 return result; 6550} 6551 6552VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo, 6553 const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) { 6554 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6555 VkResult result = dev_data->device_dispatch_table->CreateSampler(device, pCreateInfo, pAllocator, pSampler); 6556 if (VK_SUCCESS == result) { 6557 loader_platform_thread_lock_mutex(&globalLock); 6558 dev_data->sampleMap[*pSampler] = unique_ptr<SAMPLER_NODE>(new SAMPLER_NODE(pSampler, pCreateInfo)); 6559 loader_platform_thread_unlock_mutex(&globalLock); 6560 } 6561 return result; 6562} 6563 6564VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6565vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, 6566 const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) { 6567 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6568 VkResult result = dev_data->device_dispatch_table->CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout); 6569 if (VK_SUCCESS == result) { 6570 // TODOSC : Capture layout bindings set 6571 LAYOUT_NODE *pNewNode = new LAYOUT_NODE; 6572 if (NULL == pNewNode) { 6573 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, 6574 (uint64_t)*pSetLayout, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", 6575 "Out of memory while attempting to allocate LAYOUT_NODE in vkCreateDescriptorSetLayout()")) 6576 return VK_ERROR_VALIDATION_FAILED_EXT; 6577 } 6578 memcpy((void *)&pNewNode->createInfo, pCreateInfo, sizeof(VkDescriptorSetLayoutCreateInfo)); 6579 pNewNode->createInfo.pBindings = new VkDescriptorSetLayoutBinding[pCreateInfo->bindingCount]; 6580 memcpy((void *)pNewNode->createInfo.pBindings, pCreateInfo->pBindings, 6581 sizeof(VkDescriptorSetLayoutBinding) * pCreateInfo->bindingCount); 6582 // g++ does not like reserve with size 0 6583 if (pCreateInfo->bindingCount) 6584 pNewNode->bindingToIndexMap.reserve(pCreateInfo->bindingCount); 6585 uint32_t totalCount = 0; 6586 for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) { 6587 if (!pNewNode->bindingToIndexMap.emplace(pCreateInfo->pBindings[i].binding, i).second) { 6588 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 6589 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)*pSetLayout, __LINE__, 6590 DRAWSTATE_INVALID_LAYOUT, "DS", "duplicated binding number in " 6591 "VkDescriptorSetLayoutBinding")) 6592 return VK_ERROR_VALIDATION_FAILED_EXT; 6593 } else { 6594 pNewNode->bindingToIndexMap[pCreateInfo->pBindings[i].binding] = i; 6595 } 6596 totalCount += pCreateInfo->pBindings[i].descriptorCount; 6597 if (pCreateInfo->pBindings[i].pImmutableSamplers) { 6598 VkSampler **ppIS = (VkSampler **)&pNewNode->createInfo.pBindings[i].pImmutableSamplers; 6599 *ppIS = new VkSampler[pCreateInfo->pBindings[i].descriptorCount]; 6600 memcpy(*ppIS, pCreateInfo->pBindings[i].pImmutableSamplers, 6601 pCreateInfo->pBindings[i].descriptorCount * sizeof(VkSampler)); 6602 } 6603 } 6604 pNewNode->layout = *pSetLayout; 6605 pNewNode->startIndex = 0; 6606 if (totalCount > 0) { 6607 pNewNode->descriptorTypes.resize(totalCount); 6608 pNewNode->stageFlags.resize(totalCount); 6609 uint32_t offset = 0; 6610 uint32_t j = 0; 6611 VkDescriptorType dType; 6612 for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) { 6613 dType = pCreateInfo->pBindings[i].descriptorType; 6614 for (j = 0; j < pCreateInfo->pBindings[i].descriptorCount; j++) { 6615 pNewNode->descriptorTypes[offset + j] = dType; 6616 pNewNode->stageFlags[offset + j] = pCreateInfo->pBindings[i].stageFlags; 6617 if ((dType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) || 6618 (dType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) { 6619 pNewNode->dynamicDescriptorCount++; 6620 } 6621 } 6622 offset += j; 6623 } 6624 pNewNode->endIndex = pNewNode->startIndex + totalCount - 1; 6625 } else { // no descriptors 6626 pNewNode->endIndex = 0; 6627 } 6628 // Put new node at Head of global Layer list 6629 loader_platform_thread_lock_mutex(&globalLock); 6630 dev_data->descriptorSetLayoutMap[*pSetLayout] = pNewNode; 6631 loader_platform_thread_unlock_mutex(&globalLock); 6632 } 6633 return result; 6634} 6635 6636static bool validatePushConstantSize(const layer_data *dev_data, const uint32_t offset, const uint32_t size, 6637 const char *caller_name) { 6638 bool skipCall = false; 6639 if ((offset + size) > dev_data->physDevProperties.properties.limits.maxPushConstantsSize) { 6640 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 6641 DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "%s call has push constants with offset %u and size %u that " 6642 "exceeds this device's maxPushConstantSize of %u.", 6643 caller_name, offset, size, dev_data->physDevProperties.properties.limits.maxPushConstantsSize); 6644 } 6645 return skipCall; 6646} 6647 6648VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, 6649 const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) { 6650 bool skipCall = false; 6651 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6652 uint32_t i = 0; 6653 for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) { 6654 skipCall |= validatePushConstantSize(dev_data, pCreateInfo->pPushConstantRanges[i].offset, 6655 pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()"); 6656 if ((pCreateInfo->pPushConstantRanges[i].size == 0) || ((pCreateInfo->pPushConstantRanges[i].size & 0x3) != 0)) { 6657 skipCall |= 6658 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 6659 DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "vkCreatePipelineLayout() call has push constant index %u with " 6660 "size %u. Size must be greater than zero and a multiple of 4.", 6661 i, pCreateInfo->pPushConstantRanges[i].size); 6662 } 6663 // TODO : Add warning if ranges overlap 6664 } 6665 VkResult result = dev_data->device_dispatch_table->CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout); 6666 if (VK_SUCCESS == result) { 6667 loader_platform_thread_lock_mutex(&globalLock); 6668 // TODOSC : Merge capture of the setLayouts per pipeline 6669 PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout]; 6670 plNode.descriptorSetLayouts.resize(pCreateInfo->setLayoutCount); 6671 for (i = 0; i < pCreateInfo->setLayoutCount; ++i) { 6672 plNode.descriptorSetLayouts[i] = pCreateInfo->pSetLayouts[i]; 6673 } 6674 plNode.pushConstantRanges.resize(pCreateInfo->pushConstantRangeCount); 6675 for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) { 6676 plNode.pushConstantRanges[i] = pCreateInfo->pPushConstantRanges[i]; 6677 } 6678 loader_platform_thread_unlock_mutex(&globalLock); 6679 } 6680 return result; 6681} 6682 6683VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6684vkCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, 6685 VkDescriptorPool *pDescriptorPool) { 6686 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6687 VkResult result = dev_data->device_dispatch_table->CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool); 6688 if (VK_SUCCESS == result) { 6689 // Insert this pool into Global Pool LL at head 6690 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, 6691 (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", "Created Descriptor Pool %#" PRIxLEAST64, 6692 (uint64_t)*pDescriptorPool)) 6693 return VK_ERROR_VALIDATION_FAILED_EXT; 6694 DESCRIPTOR_POOL_NODE *pNewNode = new DESCRIPTOR_POOL_NODE(*pDescriptorPool, pCreateInfo); 6695 if (NULL == pNewNode) { 6696 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, 6697 (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", 6698 "Out of memory while attempting to allocate DESCRIPTOR_POOL_NODE in vkCreateDescriptorPool()")) 6699 return VK_ERROR_VALIDATION_FAILED_EXT; 6700 } else { 6701 loader_platform_thread_lock_mutex(&globalLock); 6702 dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode; 6703 loader_platform_thread_unlock_mutex(&globalLock); 6704 } 6705 } else { 6706 // Need to do anything if pool create fails? 6707 } 6708 return result; 6709} 6710 6711VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6712vkResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) { 6713 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6714 VkResult result = dev_data->device_dispatch_table->ResetDescriptorPool(device, descriptorPool, flags); 6715 if (VK_SUCCESS == result) { 6716 loader_platform_thread_lock_mutex(&globalLock); 6717 clearDescriptorPool(dev_data, device, descriptorPool, flags); 6718 loader_platform_thread_unlock_mutex(&globalLock); 6719 } 6720 return result; 6721} 6722 6723VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6724vkAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets) { 6725 VkBool32 skipCall = VK_FALSE; 6726 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6727 6728 loader_platform_thread_lock_mutex(&globalLock); 6729 // Verify that requested descriptorSets are available in pool 6730 DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool); 6731 if (!pPoolNode) { 6732 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, 6733 (uint64_t)pAllocateInfo->descriptorPool, __LINE__, DRAWSTATE_INVALID_POOL, "DS", 6734 "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call", 6735 (uint64_t)pAllocateInfo->descriptorPool); 6736 } else { // Make sure pool has all the available descriptors before calling down chain 6737 skipCall |= validate_descriptor_availability_in_pool(dev_data, pPoolNode, pAllocateInfo->descriptorSetCount, 6738 pAllocateInfo->pSetLayouts); 6739 } 6740 loader_platform_thread_unlock_mutex(&globalLock); 6741 if (skipCall) 6742 return VK_ERROR_VALIDATION_FAILED_EXT; 6743 VkResult result = dev_data->device_dispatch_table->AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets); 6744 if (VK_SUCCESS == result) { 6745 loader_platform_thread_lock_mutex(&globalLock); 6746 DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool); 6747 if (pPoolNode) { 6748 if (pAllocateInfo->descriptorSetCount == 0) { 6749 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 6750 pAllocateInfo->descriptorSetCount, __LINE__, DRAWSTATE_NONE, "DS", 6751 "AllocateDescriptorSets called with 0 count"); 6752 } 6753 for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; i++) { 6754 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 6755 (uint64_t)pDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS", "Created Descriptor Set %#" PRIxLEAST64, 6756 (uint64_t)pDescriptorSets[i]); 6757 // Create new set node and add to head of pool nodes 6758 SET_NODE *pNewNode = new SET_NODE; 6759 if (NULL == pNewNode) { 6760 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 6761 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, 6762 DRAWSTATE_OUT_OF_MEMORY, "DS", 6763 "Out of memory while attempting to allocate SET_NODE in vkAllocateDescriptorSets()")) 6764 return VK_ERROR_VALIDATION_FAILED_EXT; 6765 } else { 6766 // TODO : Pool should store a total count of each type of Descriptor available 6767 // When descriptors are allocated, decrement the count and validate here 6768 // that the count doesn't go below 0. One reset/free need to bump count back up. 6769 // Insert set at head of Set LL for this pool 6770 pNewNode->pNext = pPoolNode->pSets; 6771 pNewNode->in_use.store(0); 6772 pPoolNode->pSets = pNewNode; 6773 LAYOUT_NODE *pLayout = getLayoutNode(dev_data, pAllocateInfo->pSetLayouts[i]); 6774 if (NULL == pLayout) { 6775 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 6776 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pAllocateInfo->pSetLayouts[i], 6777 __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS", 6778 "Unable to find set layout node for layout %#" PRIxLEAST64 6779 " specified in vkAllocateDescriptorSets() call", 6780 (uint64_t)pAllocateInfo->pSetLayouts[i])) 6781 return VK_ERROR_VALIDATION_FAILED_EXT; 6782 } 6783 pNewNode->pLayout = pLayout; 6784 pNewNode->pool = pAllocateInfo->descriptorPool; 6785 pNewNode->set = pDescriptorSets[i]; 6786 pNewNode->descriptorCount = (pLayout->createInfo.bindingCount != 0) ? pLayout->endIndex + 1 : 0; 6787 if (pNewNode->descriptorCount) { 6788 size_t descriptorArraySize = sizeof(GENERIC_HEADER *) * pNewNode->descriptorCount; 6789 pNewNode->ppDescriptors = new GENERIC_HEADER *[descriptorArraySize]; 6790 memset(pNewNode->ppDescriptors, 0, descriptorArraySize); 6791 } 6792 dev_data->setMap[pDescriptorSets[i]] = pNewNode; 6793 } 6794 } 6795 } 6796 loader_platform_thread_unlock_mutex(&globalLock); 6797 } 6798 return result; 6799} 6800 6801VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6802vkFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count, const VkDescriptorSet *pDescriptorSets) { 6803 VkBool32 skipCall = VK_FALSE; 6804 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6805 // Make sure that no sets being destroyed are in-flight 6806 loader_platform_thread_lock_mutex(&globalLock); 6807 for (uint32_t i = 0; i < count; ++i) 6808 skipCall |= validateIdleDescriptorSet(dev_data, pDescriptorSets[i], "vkFreeDesriptorSets"); 6809 DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, descriptorPool); 6810 if (pPoolNode && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pPoolNode->createInfo.flags)) { 6811 // Can't Free from a NON_FREE pool 6812 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 6813 (uint64_t)device, __LINE__, DRAWSTATE_CANT_FREE_FROM_NON_FREE_POOL, "DS", 6814 "It is invalid to call vkFreeDescriptorSets() with a pool created without setting " 6815 "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT."); 6816 } 6817 loader_platform_thread_unlock_mutex(&globalLock); 6818 if (VK_FALSE != skipCall) 6819 return VK_ERROR_VALIDATION_FAILED_EXT; 6820 VkResult result = dev_data->device_dispatch_table->FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets); 6821 if (VK_SUCCESS == result) { 6822 loader_platform_thread_lock_mutex(&globalLock); 6823 6824 // Update available descriptor sets in pool 6825 pPoolNode->availableSets += count; 6826 6827 // For each freed descriptor add it back into the pool as available 6828 for (uint32_t i = 0; i < count; ++i) { 6829 SET_NODE *pSet = dev_data->setMap[pDescriptorSets[i]]; // getSetNode() without locking 6830 invalidateBoundCmdBuffers(dev_data, pSet); 6831 LAYOUT_NODE *pLayout = pSet->pLayout; 6832 uint32_t typeIndex = 0, poolSizeCount = 0; 6833 for (uint32_t j = 0; j < pLayout->createInfo.bindingCount; ++j) { 6834 typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBindings[j].descriptorType); 6835 poolSizeCount = pLayout->createInfo.pBindings[j].descriptorCount; 6836 pPoolNode->availableDescriptorTypeCount[typeIndex] += poolSizeCount; 6837 } 6838 } 6839 loader_platform_thread_unlock_mutex(&globalLock); 6840 } 6841 // TODO : Any other clean-up or book-keeping to do here? 6842 return result; 6843} 6844 6845VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6846vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites, 6847 uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) { 6848 // dsUpdate will return VK_TRUE only if a bailout error occurs, so we want to call down tree when update returns VK_FALSE 6849 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6850 loader_platform_thread_lock_mutex(&globalLock); 6851#if MTMERGESOURCE 6852 // MTMTODO : Merge this in with existing update code below and handle descriptor copies case 6853 uint32_t j = 0; 6854 for (uint32_t i = 0; i < descriptorWriteCount; ++i) { 6855 if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { 6856 for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) { 6857 dev_data->descriptorSetMap[pDescriptorWrites[i].dstSet].images.push_back( 6858 pDescriptorWrites[i].pImageInfo[j].imageView); 6859 } 6860 } else if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { 6861 for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) { 6862 dev_data->descriptorSetMap[pDescriptorWrites[i].dstSet].buffers.push_back( 6863 dev_data->bufferViewMap[pDescriptorWrites[i].pTexelBufferView[j]].buffer); 6864 } 6865 } else if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || 6866 pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) { 6867 for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) { 6868 dev_data->descriptorSetMap[pDescriptorWrites[i].dstSet].buffers.push_back( 6869 pDescriptorWrites[i].pBufferInfo[j].buffer); 6870 } 6871 } 6872 } 6873#endif 6874 VkBool32 rtn = dsUpdate(dev_data, device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies); 6875 loader_platform_thread_unlock_mutex(&globalLock); 6876 if (!rtn) { 6877 dev_data->device_dispatch_table->UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, 6878 pDescriptorCopies); 6879 } 6880} 6881 6882VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6883vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo, VkCommandBuffer *pCommandBuffer) { 6884 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6885 VkResult result = dev_data->device_dispatch_table->AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer); 6886 if (VK_SUCCESS == result) { 6887 loader_platform_thread_lock_mutex(&globalLock); 6888 auto const &cp_it = dev_data->commandPoolMap.find(pCreateInfo->commandPool); 6889 if (cp_it != dev_data->commandPoolMap.end()) { 6890 for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) { 6891 // Add command buffer to its commandPool map 6892 cp_it->second.commandBuffers.push_back(pCommandBuffer[i]); 6893 GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE; 6894 // Add command buffer to map 6895 dev_data->commandBufferMap[pCommandBuffer[i]] = pCB; 6896 resetCB(dev_data, pCommandBuffer[i]); 6897 pCB->createInfo = *pCreateInfo; 6898 pCB->device = device; 6899 } 6900 } 6901#if MTMERGESOURCE 6902 printCBList(dev_data, device); 6903#endif 6904 loader_platform_thread_unlock_mutex(&globalLock); 6905 } 6906 return result; 6907} 6908 6909VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6910vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) { 6911 VkBool32 skipCall = VK_FALSE; 6912 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 6913 loader_platform_thread_lock_mutex(&globalLock); 6914 // Validate command buffer level 6915 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 6916 if (pCB) { 6917#if MTMERGESOURCE 6918 bool commandBufferComplete = false; 6919 // MTMTODO : Merge this with code below 6920 // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references 6921 skipCall = checkCBCompleted(dev_data, commandBuffer, &commandBufferComplete); 6922 6923 if (!commandBufferComplete) { 6924 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6925 (uint64_t)commandBuffer, __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", 6926 "Calling vkBeginCommandBuffer() on active CB %p before it has completed. " 6927 "You must check CB flag before this call.", 6928 commandBuffer); 6929 } 6930#endif 6931 if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) { 6932 // Secondary Command Buffer 6933 const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo; 6934 if (!pInfo) { 6935 skipCall |= 6936 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6937 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 6938 "vkBeginCommandBuffer(): Secondary Command Buffer (%p) must have inheritance info.", 6939 reinterpret_cast<void *>(commandBuffer)); 6940 } else { 6941 if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) { 6942 if (!pInfo->renderPass) { // renderpass should NOT be null for an Secondary CB 6943 skipCall |= log_msg( 6944 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6945 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 6946 "vkBeginCommandBuffer(): Secondary Command Buffers (%p) must specify a valid renderpass parameter.", 6947 reinterpret_cast<void *>(commandBuffer)); 6948 } 6949 if (!pInfo->framebuffer) { // framebuffer may be null for an Secondary CB, but this affects perf 6950 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, 6951 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6952 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, 6953 "DS", "vkBeginCommandBuffer(): Secondary Command Buffers (%p) may perform better if a " 6954 "valid framebuffer parameter is specified.", 6955 reinterpret_cast<void *>(commandBuffer)); 6956 } else { 6957 string errorString = ""; 6958 auto fbNode = dev_data->frameBufferMap.find(pInfo->framebuffer); 6959 if (fbNode != dev_data->frameBufferMap.end()) { 6960 VkRenderPass fbRP = fbNode->second.createInfo.renderPass; 6961 if (!verify_renderpass_compatibility(dev_data, fbRP, pInfo->renderPass, errorString)) { 6962 // renderPass that framebuffer was created with 6963 // must 6964 // be compatible with local renderPass 6965 skipCall |= 6966 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 6967 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6968 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, 6969 "DS", "vkBeginCommandBuffer(): Secondary Command " 6970 "Buffer (%p) renderPass (%#" PRIxLEAST64 ") is incompatible w/ framebuffer " 6971 "(%#" PRIxLEAST64 ") w/ render pass (%#" PRIxLEAST64 ") due to: %s", 6972 reinterpret_cast<void *>(commandBuffer), (uint64_t)(pInfo->renderPass), 6973 (uint64_t)(pInfo->framebuffer), (uint64_t)(fbRP), errorString.c_str()); 6974 } 6975 // Connect this framebuffer to this cmdBuffer 6976 fbNode->second.referencingCmdBuffers.insert(pCB->commandBuffer); 6977 } 6978 } 6979 } 6980 if ((pInfo->occlusionQueryEnable == VK_FALSE || 6981 dev_data->physDevProperties.features.occlusionQueryPrecise == VK_FALSE) && 6982 (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) { 6983 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 6984 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer), 6985 __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 6986 "vkBeginCommandBuffer(): Secondary Command Buffer (%p) must not have " 6987 "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not " 6988 "support precise occlusion queries.", 6989 reinterpret_cast<void *>(commandBuffer)); 6990 } 6991 } 6992 if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) { 6993 auto rp_data = dev_data->renderPassMap.find(pInfo->renderPass); 6994 if (rp_data != dev_data->renderPassMap.end() && rp_data->second && rp_data->second->pCreateInfo) { 6995 if (pInfo->subpass >= rp_data->second->pCreateInfo->subpassCount) { 6996 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 6997 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__, 6998 DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 6999 "vkBeginCommandBuffer(): Secondary Command Buffers (%p) must has a subpass index (%d) " 7000 "that is less than the number of subpasses (%d).", 7001 (void *)commandBuffer, pInfo->subpass, rp_data->second->pCreateInfo->subpassCount); 7002 } 7003 } 7004 } 7005 } 7006 if (CB_RECORDING == pCB->state) { 7007 skipCall |= 7008 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7009 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 7010 "vkBeginCommandBuffer(): Cannot call Begin on CB (%#" PRIxLEAST64 7011 ") in the RECORDING state. Must first call vkEndCommandBuffer().", 7012 (uint64_t)commandBuffer); 7013 } else if (CB_RECORDED == pCB->state) { 7014 VkCommandPool cmdPool = pCB->createInfo.commandPool; 7015 if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) { 7016 skipCall |= 7017 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7018 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", 7019 "Call to vkBeginCommandBuffer() on command buffer (%#" PRIxLEAST64 7020 ") attempts to implicitly reset cmdBuffer created from command pool (%#" PRIxLEAST64 7021 ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.", 7022 (uint64_t)commandBuffer, (uint64_t)cmdPool); 7023 } 7024 resetCB(dev_data, commandBuffer); 7025 } 7026 // Set updated state here in case implicit reset occurs above 7027 pCB->state = CB_RECORDING; 7028 pCB->beginInfo = *pBeginInfo; 7029 if (pCB->beginInfo.pInheritanceInfo) { 7030 pCB->inheritanceInfo = *(pCB->beginInfo.pInheritanceInfo); 7031 pCB->beginInfo.pInheritanceInfo = &pCB->inheritanceInfo; 7032 } 7033 } else { 7034 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7035 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 7036 "In vkBeginCommandBuffer() and unable to find CommandBuffer Node for CB %p!", (void *)commandBuffer); 7037 } 7038 loader_platform_thread_unlock_mutex(&globalLock); 7039 if (VK_FALSE != skipCall) { 7040 return VK_ERROR_VALIDATION_FAILED_EXT; 7041 } 7042 VkResult result = dev_data->device_dispatch_table->BeginCommandBuffer(commandBuffer, pBeginInfo); 7043#if MTMERGESOURCE 7044 loader_platform_thread_lock_mutex(&globalLock); 7045 clear_cmd_buf_and_mem_references(dev_data, commandBuffer); 7046 loader_platform_thread_unlock_mutex(&globalLock); 7047#endif 7048 return result; 7049} 7050 7051VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(VkCommandBuffer commandBuffer) { 7052 VkBool32 skipCall = VK_FALSE; 7053 VkResult result = VK_SUCCESS; 7054 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7055 loader_platform_thread_lock_mutex(&globalLock); 7056 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7057 if (pCB) { 7058 if (pCB->state != CB_RECORDING) { 7059 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkEndCommandBuffer()"); 7060 } 7061 for (auto query : pCB->activeQueries) { 7062 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 7063 DRAWSTATE_INVALID_QUERY, "DS", 7064 "Ending command buffer with in progress query: queryPool %" PRIu64 ", index %d", 7065 (uint64_t)(query.pool), query.index); 7066 } 7067 } 7068 if (VK_FALSE == skipCall) { 7069 loader_platform_thread_unlock_mutex(&globalLock); 7070 result = dev_data->device_dispatch_table->EndCommandBuffer(commandBuffer); 7071 loader_platform_thread_lock_mutex(&globalLock); 7072 if (VK_SUCCESS == result) { 7073 pCB->state = CB_RECORDED; 7074 // Reset CB status flags 7075 pCB->status = 0; 7076 printCB(dev_data, commandBuffer); 7077 } 7078 } else { 7079 result = VK_ERROR_VALIDATION_FAILED_EXT; 7080 } 7081 loader_platform_thread_unlock_mutex(&globalLock); 7082 return result; 7083} 7084 7085VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 7086vkResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) { 7087 VkBool32 skipCall = VK_FALSE; 7088 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7089 loader_platform_thread_lock_mutex(&globalLock); 7090#if MTMERGESOURCE 7091 bool commandBufferComplete = false; 7092 // Verify that CB is complete (not in-flight) 7093 skipCall = checkCBCompleted(dev_data, commandBuffer, &commandBufferComplete); 7094 if (!commandBufferComplete) { 7095 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7096 (uint64_t)commandBuffer, __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", 7097 "Resetting CB %p before it has completed. You must check CB " 7098 "flag before calling vkResetCommandBuffer().", 7099 commandBuffer); 7100 } 7101 // Clear memory references as this point. 7102 clear_cmd_buf_and_mem_references(dev_data, commandBuffer); 7103#endif 7104 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7105 VkCommandPool cmdPool = pCB->createInfo.commandPool; 7106 if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) { 7107 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7108 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", 7109 "Attempt to reset command buffer (%#" PRIxLEAST64 ") created from command pool (%#" PRIxLEAST64 7110 ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.", 7111 (uint64_t)commandBuffer, (uint64_t)cmdPool); 7112 } 7113 if (dev_data->globalInFlightCmdBuffers.count(commandBuffer)) { 7114 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7115 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", 7116 "Attempt to reset command buffer (%#" PRIxLEAST64 ") which is in use.", 7117 reinterpret_cast<uint64_t>(commandBuffer)); 7118 } 7119 loader_platform_thread_unlock_mutex(&globalLock); 7120 if (skipCall != VK_FALSE) 7121 return VK_ERROR_VALIDATION_FAILED_EXT; 7122 VkResult result = dev_data->device_dispatch_table->ResetCommandBuffer(commandBuffer, flags); 7123 if (VK_SUCCESS == result) { 7124 loader_platform_thread_lock_mutex(&globalLock); 7125 resetCB(dev_data, commandBuffer); 7126 loader_platform_thread_unlock_mutex(&globalLock); 7127 } 7128 return result; 7129} 7130#if MTMERGESOURCE 7131// TODO : For any vkCmdBind* calls that include an object which has mem bound to it, 7132// need to account for that mem now having binding to given commandBuffer 7133#endif 7134VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7135vkCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) { 7136 VkBool32 skipCall = VK_FALSE; 7137 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7138 loader_platform_thread_lock_mutex(&globalLock); 7139 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7140 if (pCB) { 7141 skipCall |= addCmd(dev_data, pCB, CMD_BINDPIPELINE, "vkCmdBindPipeline()"); 7142 if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (pCB->activeRenderPass)) { 7143 skipCall |= 7144 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, 7145 (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS", 7146 "Incorrectly binding compute pipeline (%#" PRIxLEAST64 ") during active RenderPass (%#" PRIxLEAST64 ")", 7147 (uint64_t)pipeline, (uint64_t)pCB->activeRenderPass); 7148 } 7149 7150 PIPELINE_NODE *pPN = getPipeline(dev_data, pipeline); 7151 if (pPN) { 7152 pCB->lastBound[pipelineBindPoint].pipeline = pipeline; 7153 set_cb_pso_status(pCB, pPN); 7154 skipCall |= validatePipelineState(dev_data, pCB, pipelineBindPoint, pipeline); 7155 } else { 7156 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, 7157 (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_PIPELINE, "DS", 7158 "Attempt to bind Pipeline %#" PRIxLEAST64 " that doesn't exist!", (uint64_t)(pipeline)); 7159 } 7160 } 7161 loader_platform_thread_unlock_mutex(&globalLock); 7162 if (VK_FALSE == skipCall) 7163 dev_data->device_dispatch_table->CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline); 7164} 7165 7166VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7167vkCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports) { 7168 VkBool32 skipCall = VK_FALSE; 7169 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7170 loader_platform_thread_lock_mutex(&globalLock); 7171 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7172 if (pCB) { 7173 skipCall |= addCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()"); 7174 pCB->status |= CBSTATUS_VIEWPORT_SET; 7175 pCB->viewports.resize(viewportCount); 7176 memcpy(pCB->viewports.data(), pViewports, viewportCount * sizeof(VkViewport)); 7177 } 7178 loader_platform_thread_unlock_mutex(&globalLock); 7179 if (VK_FALSE == skipCall) 7180 dev_data->device_dispatch_table->CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports); 7181} 7182 7183VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7184vkCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *pScissors) { 7185 VkBool32 skipCall = VK_FALSE; 7186 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7187 loader_platform_thread_lock_mutex(&globalLock); 7188 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7189 if (pCB) { 7190 skipCall |= addCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()"); 7191 pCB->status |= CBSTATUS_SCISSOR_SET; 7192 pCB->scissors.resize(scissorCount); 7193 memcpy(pCB->scissors.data(), pScissors, scissorCount * sizeof(VkRect2D)); 7194 } 7195 loader_platform_thread_unlock_mutex(&globalLock); 7196 if (VK_FALSE == skipCall) 7197 dev_data->device_dispatch_table->CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors); 7198} 7199 7200VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) { 7201 VkBool32 skipCall = VK_FALSE; 7202 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7203 loader_platform_thread_lock_mutex(&globalLock); 7204 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7205 if (pCB) { 7206 skipCall |= addCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()"); 7207 pCB->status |= CBSTATUS_LINE_WIDTH_SET; 7208 } 7209 loader_platform_thread_unlock_mutex(&globalLock); 7210 if (VK_FALSE == skipCall) 7211 dev_data->device_dispatch_table->CmdSetLineWidth(commandBuffer, lineWidth); 7212} 7213 7214VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7215vkCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) { 7216 VkBool32 skipCall = VK_FALSE; 7217 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7218 loader_platform_thread_lock_mutex(&globalLock); 7219 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7220 if (pCB) { 7221 skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()"); 7222 pCB->status |= CBSTATUS_DEPTH_BIAS_SET; 7223 } 7224 loader_platform_thread_unlock_mutex(&globalLock); 7225 if (VK_FALSE == skipCall) 7226 dev_data->device_dispatch_table->CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, 7227 depthBiasSlopeFactor); 7228} 7229 7230VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) { 7231 VkBool32 skipCall = VK_FALSE; 7232 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7233 loader_platform_thread_lock_mutex(&globalLock); 7234 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7235 if (pCB) { 7236 skipCall |= addCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()"); 7237 pCB->status |= CBSTATUS_BLEND_SET; 7238 } 7239 loader_platform_thread_unlock_mutex(&globalLock); 7240 if (VK_FALSE == skipCall) 7241 dev_data->device_dispatch_table->CmdSetBlendConstants(commandBuffer, blendConstants); 7242} 7243 7244VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7245vkCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) { 7246 VkBool32 skipCall = VK_FALSE; 7247 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7248 loader_platform_thread_lock_mutex(&globalLock); 7249 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7250 if (pCB) { 7251 skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()"); 7252 pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET; 7253 } 7254 loader_platform_thread_unlock_mutex(&globalLock); 7255 if (VK_FALSE == skipCall) 7256 dev_data->device_dispatch_table->CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds); 7257} 7258 7259VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7260vkCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask) { 7261 VkBool32 skipCall = VK_FALSE; 7262 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7263 loader_platform_thread_lock_mutex(&globalLock); 7264 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7265 if (pCB) { 7266 skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()"); 7267 pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET; 7268 } 7269 loader_platform_thread_unlock_mutex(&globalLock); 7270 if (VK_FALSE == skipCall) 7271 dev_data->device_dispatch_table->CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask); 7272} 7273 7274VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7275vkCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) { 7276 VkBool32 skipCall = VK_FALSE; 7277 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7278 loader_platform_thread_lock_mutex(&globalLock); 7279 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7280 if (pCB) { 7281 skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()"); 7282 pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET; 7283 } 7284 loader_platform_thread_unlock_mutex(&globalLock); 7285 if (VK_FALSE == skipCall) 7286 dev_data->device_dispatch_table->CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask); 7287} 7288 7289VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7290vkCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) { 7291 VkBool32 skipCall = VK_FALSE; 7292 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7293 loader_platform_thread_lock_mutex(&globalLock); 7294 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7295 if (pCB) { 7296 skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()"); 7297 pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET; 7298 } 7299 loader_platform_thread_unlock_mutex(&globalLock); 7300 if (VK_FALSE == skipCall) 7301 dev_data->device_dispatch_table->CmdSetStencilReference(commandBuffer, faceMask, reference); 7302} 7303 7304VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7305vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, 7306 uint32_t firstSet, uint32_t setCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount, 7307 const uint32_t *pDynamicOffsets) { 7308 VkBool32 skipCall = VK_FALSE; 7309 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7310 loader_platform_thread_lock_mutex(&globalLock); 7311#if MTMERGESOURCE 7312 // MTMTODO : Merge this with code below 7313 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 7314 if (cb_data != dev_data->commandBufferMap.end()) { 7315 // MTMTODO : activeDescriptorSets should be merged with lastBound.boundDescriptorSets 7316 std::vector<VkDescriptorSet> &activeDescriptorSets = cb_data->second->activeDescriptorSets; 7317 if (activeDescriptorSets.size() < (setCount + firstSet)) { 7318 activeDescriptorSets.resize(setCount + firstSet); 7319 } 7320 for (uint32_t i = 0; i < setCount; ++i) { 7321 activeDescriptorSets[i + firstSet] = pDescriptorSets[i]; 7322 } 7323 } 7324 // TODO : Somewhere need to verify that all textures referenced by shaders in DS are in some type of *SHADER_READ* state 7325#endif 7326 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7327 if (pCB) { 7328 if (pCB->state == CB_RECORDING) { 7329 // Track total count of dynamic descriptor types to make sure we have an offset for each one 7330 uint32_t totalDynamicDescriptors = 0; 7331 string errorString = ""; 7332 uint32_t lastSetIndex = firstSet + setCount - 1; 7333 if (lastSetIndex >= pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size()) 7334 pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1); 7335 VkDescriptorSet oldFinalBoundSet = pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex]; 7336 for (uint32_t i = 0; i < setCount; i++) { 7337 SET_NODE *pSet = getSetNode(dev_data, pDescriptorSets[i]); 7338 if (pSet) { 7339 pCB->lastBound[pipelineBindPoint].uniqueBoundSets.insert(pDescriptorSets[i]); 7340 pSet->boundCmdBuffers.insert(commandBuffer); 7341 pCB->lastBound[pipelineBindPoint].pipelineLayout = layout; 7342 pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i + firstSet] = pDescriptorSets[i]; 7343 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 7344 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, 7345 DRAWSTATE_NONE, "DS", "DS %#" PRIxLEAST64 " bound on pipeline %s", 7346 (uint64_t)pDescriptorSets[i], string_VkPipelineBindPoint(pipelineBindPoint)); 7347 if (!pSet->pUpdateStructs && (pSet->descriptorCount != 0)) { 7348 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, 7349 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], 7350 __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS", 7351 "DS %#" PRIxLEAST64 7352 " bound but it was never updated. You may want to either update it or not bind it.", 7353 (uint64_t)pDescriptorSets[i]); 7354 } 7355 // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout 7356 if (!verify_set_layout_compatibility(dev_data, pSet, layout, i + firstSet, errorString)) { 7357 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7358 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], 7359 __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS", 7360 "descriptorSet #%u being bound is not compatible with overlapping layout in " 7361 "pipelineLayout due to: %s", 7362 i, errorString.c_str()); 7363 } 7364 if (pSet->pLayout->dynamicDescriptorCount) { 7365 // First make sure we won't overstep bounds of pDynamicOffsets array 7366 if ((totalDynamicDescriptors + pSet->pLayout->dynamicDescriptorCount) > dynamicOffsetCount) { 7367 skipCall |= 7368 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7369 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, 7370 DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS", 7371 "descriptorSet #%u (%#" PRIxLEAST64 7372 ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets " 7373 "array. There must be one dynamic offset for each dynamic descriptor being bound.", 7374 i, (uint64_t)pDescriptorSets[i], pSet->pLayout->dynamicDescriptorCount, 7375 (dynamicOffsetCount - totalDynamicDescriptors)); 7376 } else { // Validate and store dynamic offsets with the set 7377 // Validate Dynamic Offset Minimums 7378 uint32_t cur_dyn_offset = totalDynamicDescriptors; 7379 for (uint32_t d = 0; d < pSet->descriptorCount; d++) { 7380 if (pSet->pLayout->descriptorTypes[d] == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { 7381 if (vk_safe_modulo( 7382 pDynamicOffsets[cur_dyn_offset], 7383 dev_data->physDevProperties.properties.limits.minUniformBufferOffsetAlignment) != 7384 0) { 7385 skipCall |= log_msg( 7386 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7387 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, 7388 DRAWSTATE_INVALID_UNIFORM_BUFFER_OFFSET, "DS", 7389 "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of " 7390 "device limit minUniformBufferOffsetAlignment %#" PRIxLEAST64, 7391 cur_dyn_offset, pDynamicOffsets[cur_dyn_offset], 7392 dev_data->physDevProperties.properties.limits.minUniformBufferOffsetAlignment); 7393 } 7394 cur_dyn_offset++; 7395 } else if (pSet->pLayout->descriptorTypes[d] == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) { 7396 if (vk_safe_modulo( 7397 pDynamicOffsets[cur_dyn_offset], 7398 dev_data->physDevProperties.properties.limits.minStorageBufferOffsetAlignment) != 7399 0) { 7400 skipCall |= log_msg( 7401 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7402 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, 7403 DRAWSTATE_INVALID_STORAGE_BUFFER_OFFSET, "DS", 7404 "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of " 7405 "device limit minStorageBufferOffsetAlignment %#" PRIxLEAST64, 7406 cur_dyn_offset, pDynamicOffsets[cur_dyn_offset], 7407 dev_data->physDevProperties.properties.limits.minStorageBufferOffsetAlignment); 7408 } 7409 cur_dyn_offset++; 7410 } 7411 } 7412 // Keep running total of dynamic descriptor count to verify at the end 7413 totalDynamicDescriptors += pSet->pLayout->dynamicDescriptorCount; 7414 } 7415 } 7416 } else { 7417 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7418 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, 7419 DRAWSTATE_INVALID_SET, "DS", "Attempt to bind DS %#" PRIxLEAST64 " that doesn't exist!", 7420 (uint64_t)pDescriptorSets[i]); 7421 } 7422 skipCall |= addCmd(dev_data, pCB, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()"); 7423 // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update 7424 if (firstSet > 0) { // Check set #s below the first bound set 7425 for (uint32_t i = 0; i < firstSet; ++i) { 7426 if (pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] && 7427 !verify_set_layout_compatibility( 7428 dev_data, dev_data->setMap[pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i]], layout, i, 7429 errorString)) { 7430 skipCall |= log_msg( 7431 dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 7432 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 7433 (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS", 7434 "DescriptorSetDS %#" PRIxLEAST64 7435 " previously bound as set #%u was disturbed by newly bound pipelineLayout (%#" PRIxLEAST64 ")", 7436 (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], i, (uint64_t)layout); 7437 pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE; 7438 } 7439 } 7440 } 7441 // Check if newly last bound set invalidates any remaining bound sets 7442 if ((pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (lastSetIndex)) { 7443 if (oldFinalBoundSet && 7444 !verify_set_layout_compatibility(dev_data, dev_data->setMap[oldFinalBoundSet], layout, lastSetIndex, 7445 errorString)) { 7446 skipCall |= 7447 log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 7448 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)oldFinalBoundSet, __LINE__, 7449 DRAWSTATE_NONE, "DS", "DescriptorSetDS %#" PRIxLEAST64 7450 " previously bound as set #%u is incompatible with set %#" PRIxLEAST64 7451 " newly bound as set #%u so set #%u and any subsequent sets were " 7452 "disturbed by newly bound pipelineLayout (%#" PRIxLEAST64 ")", 7453 (uint64_t)oldFinalBoundSet, lastSetIndex, 7454 (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex], lastSetIndex, 7455 lastSetIndex + 1, (uint64_t)layout); 7456 pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1); 7457 } 7458 } 7459 // dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound 7460 if (totalDynamicDescriptors != dynamicOffsetCount) { 7461 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7462 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__, 7463 DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS", 7464 "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount " 7465 "is %u. It should exactly match the number of dynamic descriptors.", 7466 setCount, totalDynamicDescriptors, dynamicOffsetCount); 7467 } 7468 // Save dynamicOffsets bound to this CB 7469 for (uint32_t i = 0; i < dynamicOffsetCount; i++) { 7470 pCB->lastBound[pipelineBindPoint].dynamicOffsets.push_back(pDynamicOffsets[i]); 7471 } 7472 } 7473 // dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound 7474 if (totalDynamicDescriptors != dynamicOffsetCount) { 7475 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7476 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__, 7477 DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS", 7478 "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount " 7479 "is %u. It should exactly match the number of dynamic descriptors.", 7480 setCount, totalDynamicDescriptors, dynamicOffsetCount); 7481 } 7482 // Save dynamicOffsets bound to this CB 7483 for (uint32_t i = 0; i < dynamicOffsetCount; i++) { 7484 pCB->dynamicOffsets.emplace_back(pDynamicOffsets[i]); 7485 } 7486 } else { 7487 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindDescriptorSets()"); 7488 } 7489 } 7490 loader_platform_thread_unlock_mutex(&globalLock); 7491 if (VK_FALSE == skipCall) 7492 dev_data->device_dispatch_table->CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount, 7493 pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); 7494} 7495 7496VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7497vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) { 7498 VkBool32 skipCall = VK_FALSE; 7499 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7500 loader_platform_thread_lock_mutex(&globalLock); 7501#if MTMERGESOURCE 7502 VkDeviceMemory mem; 7503 skipCall = 7504 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)(buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7505 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 7506 if (cb_data != dev_data->commandBufferMap.end()) { 7507 std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBindIndexBuffer()"); }; 7508 cb_data->second->validate_functions.push_back(function); 7509 } 7510 // TODO : Somewhere need to verify that IBs have correct usage state flagged 7511#endif 7512 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7513 if (pCB) { 7514 skipCall |= addCmd(dev_data, pCB, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()"); 7515 VkDeviceSize offset_align = 0; 7516 switch (indexType) { 7517 case VK_INDEX_TYPE_UINT16: 7518 offset_align = 2; 7519 break; 7520 case VK_INDEX_TYPE_UINT32: 7521 offset_align = 4; 7522 break; 7523 default: 7524 // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0 7525 break; 7526 } 7527 if (!offset_align || (offset % offset_align)) { 7528 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 7529 DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS", 7530 "vkCmdBindIndexBuffer() offset (%#" PRIxLEAST64 ") does not fall on alignment (%s) boundary.", 7531 offset, string_VkIndexType(indexType)); 7532 } 7533 pCB->status |= CBSTATUS_INDEX_BUFFER_BOUND; 7534 } 7535 loader_platform_thread_unlock_mutex(&globalLock); 7536 if (VK_FALSE == skipCall) 7537 dev_data->device_dispatch_table->CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType); 7538} 7539 7540void updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) { 7541 uint32_t end = firstBinding + bindingCount; 7542 if (pCB->currentDrawData.buffers.size() < end) { 7543 pCB->currentDrawData.buffers.resize(end); 7544 } 7545 for (uint32_t i = 0; i < bindingCount; ++i) { 7546 pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i]; 7547 } 7548} 7549 7550void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); } 7551 7552VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, 7553 uint32_t bindingCount, const VkBuffer *pBuffers, 7554 const VkDeviceSize *pOffsets) { 7555 VkBool32 skipCall = VK_FALSE; 7556 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7557 loader_platform_thread_lock_mutex(&globalLock); 7558#if MTMERGESOURCE 7559 for (uint32_t i = 0; i < bindingCount; ++i) { 7560 VkDeviceMemory mem; 7561 skipCall |= get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)(pBuffers[i]), 7562 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7563 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 7564 if (cb_data != dev_data->commandBufferMap.end()) { 7565 std::function<VkBool32()> function = 7566 [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBindVertexBuffers()"); }; 7567 cb_data->second->validate_functions.push_back(function); 7568 } 7569 } 7570 // TODO : Somewhere need to verify that VBs have correct usage state flagged 7571#endif 7572 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7573 if (pCB) { 7574 addCmd(dev_data, pCB, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffer()"); 7575 updateResourceTracking(pCB, firstBinding, bindingCount, pBuffers); 7576 } else { 7577 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindVertexBuffer()"); 7578 } 7579 loader_platform_thread_unlock_mutex(&globalLock); 7580 if (VK_FALSE == skipCall) 7581 dev_data->device_dispatch_table->CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); 7582} 7583 7584#if MTMERGESOURCE 7585/* expects globalLock to be held by caller */ 7586bool markStoreImagesAndBuffersAsWritten(VkCommandBuffer commandBuffer) { 7587 bool skip_call = false; 7588 layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7589 auto cb_data = my_data->commandBufferMap.find(commandBuffer); 7590 if (cb_data == my_data->commandBufferMap.end()) 7591 return skip_call; 7592 std::vector<VkDescriptorSet> &activeDescriptorSets = cb_data->second->activeDescriptorSets; 7593 for (auto descriptorSet : activeDescriptorSets) { 7594 auto ds_data = my_data->descriptorSetMap.find(descriptorSet); 7595 if (ds_data == my_data->descriptorSetMap.end()) 7596 continue; 7597 std::vector<VkImageView> images = ds_data->second.images; 7598 std::vector<VkBuffer> buffers = ds_data->second.buffers; 7599 for (auto imageView : images) { 7600 auto iv_data = my_data->imageViewMap.find(imageView); 7601 if (iv_data == my_data->imageViewMap.end()) 7602 continue; 7603 VkImage image = iv_data->second.image; 7604 VkDeviceMemory mem; 7605 skip_call |= 7606 get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 7607 std::function<VkBool32()> function = [=]() { 7608 set_memory_valid(my_data, mem, true, image); 7609 return VK_FALSE; 7610 }; 7611 cb_data->second->validate_functions.push_back(function); 7612 } 7613 for (auto buffer : buffers) { 7614 VkDeviceMemory mem; 7615 skip_call |= 7616 get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7617 std::function<VkBool32()> function = [=]() { 7618 set_memory_valid(my_data, mem, true); 7619 return VK_FALSE; 7620 }; 7621 cb_data->second->validate_functions.push_back(function); 7622 } 7623 } 7624 return skip_call; 7625} 7626#endif 7627 7628VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, 7629 uint32_t firstVertex, uint32_t firstInstance) { 7630 VkBool32 skipCall = VK_FALSE; 7631 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7632 loader_platform_thread_lock_mutex(&globalLock); 7633#if MTMERGESOURCE 7634 // MTMTODO : merge with code below 7635 skipCall = markStoreImagesAndBuffersAsWritten(commandBuffer); 7636#endif 7637 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7638 if (pCB) { 7639 skipCall |= addCmd(dev_data, pCB, CMD_DRAW, "vkCmdDraw()"); 7640 pCB->drawCount[DRAW]++; 7641 skipCall |= validate_draw_state(dev_data, pCB, VK_FALSE); 7642 // TODO : Need to pass commandBuffer as srcObj here 7643 skipCall |= 7644 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 7645 __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDraw() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW]++); 7646 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); 7647 if (VK_FALSE == skipCall) { 7648 updateResourceTrackingOnDraw(pCB); 7649 } 7650 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDraw"); 7651 } 7652 loader_platform_thread_unlock_mutex(&globalLock); 7653 if (VK_FALSE == skipCall) 7654 dev_data->device_dispatch_table->CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance); 7655} 7656 7657VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, 7658 uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, 7659 uint32_t firstInstance) { 7660 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7661 VkBool32 skipCall = VK_FALSE; 7662 loader_platform_thread_lock_mutex(&globalLock); 7663#if MTMERGESOURCE 7664 // MTMTODO : merge with code below 7665 skipCall = markStoreImagesAndBuffersAsWritten(commandBuffer); 7666#endif 7667 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7668 if (pCB) { 7669 skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXED, "vkCmdDrawIndexed()"); 7670 pCB->drawCount[DRAW_INDEXED]++; 7671 skipCall |= validate_draw_state(dev_data, pCB, VK_TRUE); 7672 // TODO : Need to pass commandBuffer as srcObj here 7673 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 7674 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS", 7675 "vkCmdDrawIndexed() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW_INDEXED]++); 7676 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); 7677 if (VK_FALSE == skipCall) { 7678 updateResourceTrackingOnDraw(pCB); 7679 } 7680 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexed"); 7681 } 7682 loader_platform_thread_unlock_mutex(&globalLock); 7683 if (VK_FALSE == skipCall) 7684 dev_data->device_dispatch_table->CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, 7685 firstInstance); 7686} 7687 7688VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7689vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { 7690 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7691 VkBool32 skipCall = VK_FALSE; 7692 loader_platform_thread_lock_mutex(&globalLock); 7693#if MTMERGESOURCE 7694 VkDeviceMemory mem; 7695 // MTMTODO : merge with code below 7696 skipCall = 7697 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7698 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDrawIndirect"); 7699 skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer); 7700#endif 7701 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7702 if (pCB) { 7703 skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDIRECT, "vkCmdDrawIndirect()"); 7704 pCB->drawCount[DRAW_INDIRECT]++; 7705 skipCall |= validate_draw_state(dev_data, pCB, VK_FALSE); 7706 // TODO : Need to pass commandBuffer as srcObj here 7707 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 7708 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS", 7709 "vkCmdDrawIndirect() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW_INDIRECT]++); 7710 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); 7711 if (VK_FALSE == skipCall) { 7712 updateResourceTrackingOnDraw(pCB); 7713 } 7714 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndirect"); 7715 } 7716 loader_platform_thread_unlock_mutex(&globalLock); 7717 if (VK_FALSE == skipCall) 7718 dev_data->device_dispatch_table->CmdDrawIndirect(commandBuffer, buffer, offset, count, stride); 7719} 7720 7721VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7722vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { 7723 VkBool32 skipCall = VK_FALSE; 7724 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7725 loader_platform_thread_lock_mutex(&globalLock); 7726#if MTMERGESOURCE 7727 VkDeviceMemory mem; 7728 // MTMTODO : merge with code below 7729 skipCall = 7730 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7731 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDrawIndexedIndirect"); 7732 skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer); 7733#endif 7734 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7735 if (pCB) { 7736 skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXEDINDIRECT, "vkCmdDrawIndexedIndirect()"); 7737 pCB->drawCount[DRAW_INDEXED_INDIRECT]++; 7738 loader_platform_thread_unlock_mutex(&globalLock); 7739 skipCall |= validate_draw_state(dev_data, pCB, VK_TRUE); 7740 loader_platform_thread_lock_mutex(&globalLock); 7741 // TODO : Need to pass commandBuffer as srcObj here 7742 skipCall |= 7743 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 7744 __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDrawIndexedIndirect() call #%" PRIu64 ", reporting DS state:", 7745 g_drawCount[DRAW_INDEXED_INDIRECT]++); 7746 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); 7747 if (VK_FALSE == skipCall) { 7748 updateResourceTrackingOnDraw(pCB); 7749 } 7750 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexedIndirect"); 7751 } 7752 loader_platform_thread_unlock_mutex(&globalLock); 7753 if (VK_FALSE == skipCall) 7754 dev_data->device_dispatch_table->CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride); 7755} 7756 7757VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) { 7758 VkBool32 skipCall = VK_FALSE; 7759 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7760 loader_platform_thread_lock_mutex(&globalLock); 7761#if MTMERGESOURCE 7762 skipCall = markStoreImagesAndBuffersAsWritten(commandBuffer); 7763#endif 7764 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7765 if (pCB) { 7766 skipCall |= addCmd(dev_data, pCB, CMD_DISPATCH, "vkCmdDispatch()"); 7767 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatch"); 7768 } 7769 loader_platform_thread_unlock_mutex(&globalLock); 7770 if (VK_FALSE == skipCall) 7771 dev_data->device_dispatch_table->CmdDispatch(commandBuffer, x, y, z); 7772} 7773 7774VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7775vkCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) { 7776 VkBool32 skipCall = VK_FALSE; 7777 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7778 loader_platform_thread_lock_mutex(&globalLock); 7779#if MTMERGESOURCE 7780 VkDeviceMemory mem; 7781 skipCall = 7782 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7783 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDispatchIndirect"); 7784 skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer); 7785#endif 7786 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7787 if (pCB) { 7788 skipCall |= addCmd(dev_data, pCB, CMD_DISPATCHINDIRECT, "vkCmdDispatchIndirect()"); 7789 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatchIndirect"); 7790 } 7791 loader_platform_thread_unlock_mutex(&globalLock); 7792 if (VK_FALSE == skipCall) 7793 dev_data->device_dispatch_table->CmdDispatchIndirect(commandBuffer, buffer, offset); 7794} 7795 7796VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, 7797 uint32_t regionCount, const VkBufferCopy *pRegions) { 7798 VkBool32 skipCall = VK_FALSE; 7799 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7800 loader_platform_thread_lock_mutex(&globalLock); 7801#if MTMERGESOURCE 7802 VkDeviceMemory mem; 7803 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 7804 loader_platform_thread_lock_mutex(&globalLock); 7805 skipCall = 7806 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7807 if (cb_data != dev_data->commandBufferMap.end()) { 7808 std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyBuffer()"); }; 7809 cb_data->second->validate_functions.push_back(function); 7810 } 7811 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBuffer"); 7812 skipCall |= 7813 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7814 if (cb_data != dev_data->commandBufferMap.end()) { 7815 std::function<VkBool32()> function = [=]() { 7816 set_memory_valid(dev_data, mem, true); 7817 return VK_FALSE; 7818 }; 7819 cb_data->second->validate_functions.push_back(function); 7820 } 7821 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBuffer"); 7822 // Validate that SRC & DST buffers have correct usage flags set 7823 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, 7824 "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT"); 7825 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, 7826 "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); 7827#endif 7828 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7829 if (pCB) { 7830 skipCall |= addCmd(dev_data, pCB, CMD_COPYBUFFER, "vkCmdCopyBuffer()"); 7831 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyBuffer"); 7832 } 7833 loader_platform_thread_unlock_mutex(&globalLock); 7834 if (VK_FALSE == skipCall) 7835 dev_data->device_dispatch_table->CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); 7836} 7837 7838VkBool32 VerifySourceImageLayout(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageSubresourceLayers subLayers, 7839 VkImageLayout srcImageLayout) { 7840 VkBool32 skip_call = VK_FALSE; 7841 7842 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 7843 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 7844 for (uint32_t i = 0; i < subLayers.layerCount; ++i) { 7845 uint32_t layer = i + subLayers.baseArrayLayer; 7846 VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer}; 7847 IMAGE_CMD_BUF_LAYOUT_NODE node; 7848 if (!FindLayout(pCB, srcImage, sub, node)) { 7849 SetLayout(pCB, srcImage, sub, {srcImageLayout, srcImageLayout}); 7850 continue; 7851 } 7852 if (node.layout != srcImageLayout) { 7853 // TODO: Improve log message in the next pass 7854 skip_call |= 7855 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 7856 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose source layout is %s " 7857 "and doesn't match the current layout %s.", 7858 string_VkImageLayout(srcImageLayout), string_VkImageLayout(node.layout)); 7859 } 7860 } 7861 if (srcImageLayout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { 7862 if (srcImageLayout == VK_IMAGE_LAYOUT_GENERAL) { 7863 // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning. 7864 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 7865 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 7866 "Layout for input image should be TRANSFER_SRC_OPTIMAL instead of GENERAL."); 7867 } else { 7868 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 7869 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for input image is %s but can only be " 7870 "TRANSFER_SRC_OPTIMAL or GENERAL.", 7871 string_VkImageLayout(srcImageLayout)); 7872 } 7873 } 7874 return skip_call; 7875} 7876 7877VkBool32 VerifyDestImageLayout(VkCommandBuffer cmdBuffer, VkImage destImage, VkImageSubresourceLayers subLayers, 7878 VkImageLayout destImageLayout) { 7879 VkBool32 skip_call = VK_FALSE; 7880 7881 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 7882 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 7883 for (uint32_t i = 0; i < subLayers.layerCount; ++i) { 7884 uint32_t layer = i + subLayers.baseArrayLayer; 7885 VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer}; 7886 IMAGE_CMD_BUF_LAYOUT_NODE node; 7887 if (!FindLayout(pCB, destImage, sub, node)) { 7888 SetLayout(pCB, destImage, sub, {destImageLayout, destImageLayout}); 7889 continue; 7890 } 7891 if (node.layout != destImageLayout) { 7892 skip_call |= 7893 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 7894 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose dest layout is %s and " 7895 "doesn't match the current layout %s.", 7896 string_VkImageLayout(destImageLayout), string_VkImageLayout(node.layout)); 7897 } 7898 } 7899 if (destImageLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { 7900 if (destImageLayout == VK_IMAGE_LAYOUT_GENERAL) { 7901 // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning. 7902 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 7903 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 7904 "Layout for output image should be TRANSFER_DST_OPTIMAL instead of GENERAL."); 7905 } else { 7906 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 7907 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for output image is %s but can only be " 7908 "TRANSFER_DST_OPTIMAL or GENERAL.", 7909 string_VkImageLayout(destImageLayout)); 7910 } 7911 } 7912 return skip_call; 7913} 7914 7915VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7916vkCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, 7917 VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) { 7918 VkBool32 skipCall = VK_FALSE; 7919 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7920 loader_platform_thread_lock_mutex(&globalLock); 7921#if MTMERGESOURCE 7922 VkDeviceMemory mem; 7923 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 7924 // Validate that src & dst images have correct usage flags set 7925 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 7926 if (cb_data != dev_data->commandBufferMap.end()) { 7927 std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyImage()", srcImage); }; 7928 cb_data->second->validate_functions.push_back(function); 7929 } 7930 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImage"); 7931 skipCall |= 7932 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 7933 if (cb_data != dev_data->commandBufferMap.end()) { 7934 std::function<VkBool32()> function = [=]() { 7935 set_memory_valid(dev_data, mem, true, dstImage); 7936 return VK_FALSE; 7937 }; 7938 cb_data->second->validate_functions.push_back(function); 7939 } 7940 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImage"); 7941 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, 7942 "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT"); 7943 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, 7944 "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT"); 7945#endif 7946 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7947 if (pCB) { 7948 skipCall |= addCmd(dev_data, pCB, CMD_COPYIMAGE, "vkCmdCopyImage()"); 7949 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyImage"); 7950 for (uint32_t i = 0; i < regionCount; ++i) { 7951 skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].srcSubresource, srcImageLayout); 7952 skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].dstSubresource, dstImageLayout); 7953 } 7954 } 7955 loader_platform_thread_unlock_mutex(&globalLock); 7956 if (VK_FALSE == skipCall) 7957 dev_data->device_dispatch_table->CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, 7958 regionCount, pRegions); 7959} 7960 7961VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7962vkCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, 7963 VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) { 7964 VkBool32 skipCall = VK_FALSE; 7965 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7966 loader_platform_thread_lock_mutex(&globalLock); 7967#if MTMERGESOURCE 7968 VkDeviceMemory mem; 7969 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 7970 // Validate that src & dst images have correct usage flags set 7971 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 7972 if (cb_data != dev_data->commandBufferMap.end()) { 7973 std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBlitImage()", srcImage); }; 7974 cb_data->second->validate_functions.push_back(function); 7975 } 7976 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdBlitImage"); 7977 skipCall |= 7978 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 7979 if (cb_data != dev_data->commandBufferMap.end()) { 7980 std::function<VkBool32()> function = [=]() { 7981 set_memory_valid(dev_data, mem, true, dstImage); 7982 return VK_FALSE; 7983 }; 7984 cb_data->second->validate_functions.push_back(function); 7985 } 7986 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdBlitImage"); 7987 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, 7988 "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT"); 7989 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, 7990 "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT"); 7991#endif 7992 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7993 if (pCB) { 7994 skipCall |= addCmd(dev_data, pCB, CMD_BLITIMAGE, "vkCmdBlitImage()"); 7995 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdBlitImage"); 7996 } 7997 loader_platform_thread_unlock_mutex(&globalLock); 7998 if (VK_FALSE == skipCall) 7999 dev_data->device_dispatch_table->CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, 8000 regionCount, pRegions, filter); 8001} 8002 8003VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, 8004 VkImage dstImage, VkImageLayout dstImageLayout, 8005 uint32_t regionCount, const VkBufferImageCopy *pRegions) { 8006 VkBool32 skipCall = VK_FALSE; 8007 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8008 loader_platform_thread_lock_mutex(&globalLock); 8009#if MTMERGESOURCE 8010 VkDeviceMemory mem; 8011 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 8012 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8013 if (cb_data != dev_data->commandBufferMap.end()) { 8014 std::function<VkBool32()> function = [=]() { 8015 set_memory_valid(dev_data, mem, true, dstImage); 8016 return VK_FALSE; 8017 }; 8018 cb_data->second->validate_functions.push_back(function); 8019 } 8020 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBufferToImage"); 8021 skipCall |= 8022 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 8023 if (cb_data != dev_data->commandBufferMap.end()) { 8024 std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyBufferToImage()"); }; 8025 cb_data->second->validate_functions.push_back(function); 8026 } 8027 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBufferToImage"); 8028 // Validate that src buff & dst image have correct usage flags set 8029 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, 8030 "vkCmdCopyBufferToImage()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT"); 8031 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, 8032 "vkCmdCopyBufferToImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT"); 8033#endif 8034 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8035 if (pCB) { 8036 skipCall |= addCmd(dev_data, pCB, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()"); 8037 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyBufferToImage"); 8038 for (uint32_t i = 0; i < regionCount; ++i) { 8039 skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].imageSubresource, dstImageLayout); 8040 } 8041 } 8042 loader_platform_thread_unlock_mutex(&globalLock); 8043 if (VK_FALSE == skipCall) 8044 dev_data->device_dispatch_table->CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, 8045 pRegions); 8046} 8047 8048VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, 8049 VkImageLayout srcImageLayout, VkBuffer dstBuffer, 8050 uint32_t regionCount, const VkBufferImageCopy *pRegions) { 8051 VkBool32 skipCall = VK_FALSE; 8052 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8053 loader_platform_thread_lock_mutex(&globalLock); 8054#if MTMERGESOURCE 8055 VkDeviceMemory mem; 8056 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 8057 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8058 if (cb_data != dev_data->commandBufferMap.end()) { 8059 std::function<VkBool32()> function = 8060 [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyImageToBuffer()", srcImage); }; 8061 cb_data->second->validate_functions.push_back(function); 8062 } 8063 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImageToBuffer"); 8064 skipCall |= 8065 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 8066 if (cb_data != dev_data->commandBufferMap.end()) { 8067 std::function<VkBool32()> function = [=]() { 8068 set_memory_valid(dev_data, mem, true); 8069 return VK_FALSE; 8070 }; 8071 cb_data->second->validate_functions.push_back(function); 8072 } 8073 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImageToBuffer"); 8074 // Validate that dst buff & src image have correct usage flags set 8075 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, 8076 "vkCmdCopyImageToBuffer()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT"); 8077 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, 8078 "vkCmdCopyImageToBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); 8079#endif 8080 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8081 if (pCB) { 8082 skipCall |= addCmd(dev_data, pCB, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()"); 8083 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyImageToBuffer"); 8084 for (uint32_t i = 0; i < regionCount; ++i) { 8085 skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].imageSubresource, srcImageLayout); 8086 } 8087 } 8088 loader_platform_thread_unlock_mutex(&globalLock); 8089 if (VK_FALSE == skipCall) 8090 dev_data->device_dispatch_table->CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, 8091 pRegions); 8092} 8093 8094VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, 8095 VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t *pData) { 8096 VkBool32 skipCall = VK_FALSE; 8097 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8098 loader_platform_thread_lock_mutex(&globalLock); 8099#if MTMERGESOURCE 8100 VkDeviceMemory mem; 8101 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 8102 skipCall = 8103 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 8104 if (cb_data != dev_data->commandBufferMap.end()) { 8105 std::function<VkBool32()> function = [=]() { 8106 set_memory_valid(dev_data, mem, true); 8107 return VK_FALSE; 8108 }; 8109 cb_data->second->validate_functions.push_back(function); 8110 } 8111 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdUpdateBuffer"); 8112 // Validate that dst buff has correct usage flags set 8113 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, 8114 "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); 8115#endif 8116 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8117 if (pCB) { 8118 skipCall |= addCmd(dev_data, pCB, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()"); 8119 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyUpdateBuffer"); 8120 } 8121 loader_platform_thread_unlock_mutex(&globalLock); 8122 if (VK_FALSE == skipCall) 8123 dev_data->device_dispatch_table->CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData); 8124} 8125 8126VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8127vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) { 8128 VkBool32 skipCall = VK_FALSE; 8129 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8130 loader_platform_thread_lock_mutex(&globalLock); 8131#if MTMERGESOURCE 8132 VkDeviceMemory mem; 8133 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 8134 skipCall = 8135 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 8136 if (cb_data != dev_data->commandBufferMap.end()) { 8137 std::function<VkBool32()> function = [=]() { 8138 set_memory_valid(dev_data, mem, true); 8139 return VK_FALSE; 8140 }; 8141 cb_data->second->validate_functions.push_back(function); 8142 } 8143 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdFillBuffer"); 8144 // Validate that dst buff has correct usage flags set 8145 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, 8146 "vkCmdFillBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); 8147#endif 8148 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8149 if (pCB) { 8150 skipCall |= addCmd(dev_data, pCB, CMD_FILLBUFFER, "vkCmdFillBuffer()"); 8151 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyFillBuffer"); 8152 } 8153 loader_platform_thread_unlock_mutex(&globalLock); 8154 if (VK_FALSE == skipCall) 8155 dev_data->device_dispatch_table->CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data); 8156} 8157 8158VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, 8159 const VkClearAttachment *pAttachments, uint32_t rectCount, 8160 const VkClearRect *pRects) { 8161 VkBool32 skipCall = VK_FALSE; 8162 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8163 loader_platform_thread_lock_mutex(&globalLock); 8164 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8165 if (pCB) { 8166 skipCall |= addCmd(dev_data, pCB, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()"); 8167 // Warn if this is issued prior to Draw Cmd and clearing the entire attachment 8168 if (!hasDrawCmd(pCB) && (pCB->activeRenderPassBeginInfo.renderArea.extent.width == pRects[0].rect.extent.width) && 8169 (pCB->activeRenderPassBeginInfo.renderArea.extent.height == pRects[0].rect.extent.height)) { 8170 // TODO : commandBuffer should be srcObj 8171 // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass) 8172 // Can we make this warning more specific? I'd like to avoid triggering this test if we can tell it's a use that must 8173 // call CmdClearAttachments 8174 // Otherwise this seems more like a performance warning. 8175 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 8176 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 0, DRAWSTATE_CLEAR_CMD_BEFORE_DRAW, "DS", 8177 "vkCmdClearAttachments() issued on CB object 0x%" PRIxLEAST64 " prior to any Draw Cmds." 8178 " It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.", 8179 (uint64_t)(commandBuffer)); 8180 } 8181 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdClearAttachments"); 8182 } 8183 8184 // Validate that attachment is in reference list of active subpass 8185 if (pCB->activeRenderPass) { 8186 const VkRenderPassCreateInfo *pRPCI = dev_data->renderPassMap[pCB->activeRenderPass]->pCreateInfo; 8187 const VkSubpassDescription *pSD = &pRPCI->pSubpasses[pCB->activeSubpass]; 8188 8189 for (uint32_t attachment_idx = 0; attachment_idx < attachmentCount; attachment_idx++) { 8190 const VkClearAttachment *attachment = &pAttachments[attachment_idx]; 8191 if (attachment->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { 8192 VkBool32 found = VK_FALSE; 8193 for (uint32_t i = 0; i < pSD->colorAttachmentCount; i++) { 8194 if (attachment->colorAttachment == pSD->pColorAttachments[i].attachment) { 8195 found = VK_TRUE; 8196 break; 8197 } 8198 } 8199 if (VK_FALSE == found) { 8200 skipCall |= log_msg( 8201 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 8202 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS", 8203 "vkCmdClearAttachments() attachment index %d not found in attachment reference array of active subpass %d", 8204 attachment->colorAttachment, pCB->activeSubpass); 8205 } 8206 } else if (attachment->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { 8207 if (!pSD->pDepthStencilAttachment || // Says no DS will be used in active subpass 8208 (pSD->pDepthStencilAttachment->attachment == 8209 VK_ATTACHMENT_UNUSED)) { // Says no DS will be used in active subpass 8210 8211 skipCall |= log_msg( 8212 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 8213 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS", 8214 "vkCmdClearAttachments() attachment index %d does not match depthStencilAttachment.attachment (%d) found " 8215 "in active subpass %d", 8216 attachment->colorAttachment, 8217 (pSD->pDepthStencilAttachment) ? pSD->pDepthStencilAttachment->attachment : VK_ATTACHMENT_UNUSED, 8218 pCB->activeSubpass); 8219 } 8220 } 8221 } 8222 } 8223 loader_platform_thread_unlock_mutex(&globalLock); 8224 if (VK_FALSE == skipCall) 8225 dev_data->device_dispatch_table->CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects); 8226} 8227 8228VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, 8229 VkImageLayout imageLayout, const VkClearColorValue *pColor, 8230 uint32_t rangeCount, const VkImageSubresourceRange *pRanges) { 8231 VkBool32 skipCall = VK_FALSE; 8232 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8233 loader_platform_thread_lock_mutex(&globalLock); 8234#if MTMERGESOURCE 8235 // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state 8236 VkDeviceMemory mem; 8237 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 8238 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8239 if (cb_data != dev_data->commandBufferMap.end()) { 8240 std::function<VkBool32()> function = [=]() { 8241 set_memory_valid(dev_data, mem, true, image); 8242 return VK_FALSE; 8243 }; 8244 cb_data->second->validate_functions.push_back(function); 8245 } 8246 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdClearColorImage"); 8247#endif 8248 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8249 if (pCB) { 8250 skipCall |= addCmd(dev_data, pCB, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()"); 8251 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdClearColorImage"); 8252 } 8253 loader_platform_thread_unlock_mutex(&globalLock); 8254 if (VK_FALSE == skipCall) 8255 dev_data->device_dispatch_table->CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges); 8256} 8257 8258VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8259vkCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, 8260 const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount, 8261 const VkImageSubresourceRange *pRanges) { 8262 VkBool32 skipCall = VK_FALSE; 8263 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8264 loader_platform_thread_lock_mutex(&globalLock); 8265#if MTMERGESOURCE 8266 // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state 8267 VkDeviceMemory mem; 8268 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 8269 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8270 if (cb_data != dev_data->commandBufferMap.end()) { 8271 std::function<VkBool32()> function = [=]() { 8272 set_memory_valid(dev_data, mem, true, image); 8273 return VK_FALSE; 8274 }; 8275 cb_data->second->validate_functions.push_back(function); 8276 } 8277 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdClearDepthStencilImage"); 8278#endif 8279 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8280 if (pCB) { 8281 skipCall |= addCmd(dev_data, pCB, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()"); 8282 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdClearDepthStencilImage"); 8283 } 8284 loader_platform_thread_unlock_mutex(&globalLock); 8285 if (VK_FALSE == skipCall) 8286 dev_data->device_dispatch_table->CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, 8287 pRanges); 8288} 8289 8290VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8291vkCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, 8292 VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve *pRegions) { 8293 VkBool32 skipCall = VK_FALSE; 8294 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8295 loader_platform_thread_lock_mutex(&globalLock); 8296#if MTMERGESOURCE 8297 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 8298 VkDeviceMemory mem; 8299 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8300 if (cb_data != dev_data->commandBufferMap.end()) { 8301 std::function<VkBool32()> function = 8302 [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdResolveImage()", srcImage); }; 8303 cb_data->second->validate_functions.push_back(function); 8304 } 8305 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdResolveImage"); 8306 skipCall |= 8307 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8308 if (cb_data != dev_data->commandBufferMap.end()) { 8309 std::function<VkBool32()> function = [=]() { 8310 set_memory_valid(dev_data, mem, true, dstImage); 8311 return VK_FALSE; 8312 }; 8313 cb_data->second->validate_functions.push_back(function); 8314 } 8315 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdResolveImage"); 8316#endif 8317 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8318 if (pCB) { 8319 skipCall |= addCmd(dev_data, pCB, CMD_RESOLVEIMAGE, "vkCmdResolveImage()"); 8320 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdResolveImage"); 8321 } 8322 loader_platform_thread_unlock_mutex(&globalLock); 8323 if (VK_FALSE == skipCall) 8324 dev_data->device_dispatch_table->CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, 8325 regionCount, pRegions); 8326} 8327 8328bool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { 8329 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8330 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8331 if (pCB) { 8332 pCB->eventToStageMap[event] = stageMask; 8333 } 8334 auto queue_data = dev_data->queueMap.find(queue); 8335 if (queue_data != dev_data->queueMap.end()) { 8336 queue_data->second.eventToStageMap[event] = stageMask; 8337 } 8338 return false; 8339} 8340 8341VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8342vkCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { 8343 VkBool32 skipCall = VK_FALSE; 8344 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8345 loader_platform_thread_lock_mutex(&globalLock); 8346 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8347 if (pCB) { 8348 skipCall |= addCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()"); 8349 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent"); 8350 pCB->events.push_back(event); 8351 std::function<bool(VkQueue)> eventUpdate = 8352 std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, stageMask); 8353 pCB->eventUpdates.push_back(eventUpdate); 8354 } 8355 loader_platform_thread_unlock_mutex(&globalLock); 8356 if (VK_FALSE == skipCall) 8357 dev_data->device_dispatch_table->CmdSetEvent(commandBuffer, event, stageMask); 8358} 8359 8360VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8361vkCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { 8362 VkBool32 skipCall = VK_FALSE; 8363 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8364 loader_platform_thread_lock_mutex(&globalLock); 8365 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8366 if (pCB) { 8367 skipCall |= addCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()"); 8368 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent"); 8369 pCB->events.push_back(event); 8370 std::function<bool(VkQueue)> eventUpdate = 8371 std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, VkPipelineStageFlags(0)); 8372 pCB->eventUpdates.push_back(eventUpdate); 8373 } 8374 loader_platform_thread_unlock_mutex(&globalLock); 8375 if (VK_FALSE == skipCall) 8376 dev_data->device_dispatch_table->CmdResetEvent(commandBuffer, event, stageMask); 8377} 8378 8379VkBool32 TransitionImageLayouts(VkCommandBuffer cmdBuffer, uint32_t memBarrierCount, const VkImageMemoryBarrier *pImgMemBarriers) { 8380 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 8381 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 8382 VkBool32 skip = VK_FALSE; 8383 uint32_t levelCount = 0; 8384 uint32_t layerCount = 0; 8385 8386 for (uint32_t i = 0; i < memBarrierCount; ++i) { 8387 auto mem_barrier = &pImgMemBarriers[i]; 8388 if (!mem_barrier) 8389 continue; 8390 // TODO: Do not iterate over every possibility - consolidate where 8391 // possible 8392 ResolveRemainingLevelsLayers(dev_data, &levelCount, &layerCount, mem_barrier->subresourceRange, mem_barrier->image); 8393 8394 for (uint32_t j = 0; j < levelCount; j++) { 8395 uint32_t level = mem_barrier->subresourceRange.baseMipLevel + j; 8396 for (uint32_t k = 0; k < layerCount; k++) { 8397 uint32_t layer = mem_barrier->subresourceRange.baseArrayLayer + k; 8398 VkImageSubresource sub = {mem_barrier->subresourceRange.aspectMask, level, layer}; 8399 IMAGE_CMD_BUF_LAYOUT_NODE node; 8400 if (!FindLayout(pCB, mem_barrier->image, sub, node)) { 8401 SetLayout(pCB, mem_barrier->image, sub, {mem_barrier->oldLayout, mem_barrier->newLayout}); 8402 continue; 8403 } 8404 if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) { 8405 // TODO: Set memory invalid which is in mem_tracker currently 8406 } else if (node.layout != mem_barrier->oldLayout) { 8407 skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 8408 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "You cannot transition the layout from %s " 8409 "when current layout is %s.", 8410 string_VkImageLayout(mem_barrier->oldLayout), string_VkImageLayout(node.layout)); 8411 } 8412 SetLayout(pCB, mem_barrier->image, sub, mem_barrier->newLayout); 8413 } 8414 } 8415 } 8416 return skip; 8417} 8418 8419// Print readable FlagBits in FlagMask 8420std::string string_VkAccessFlags(VkAccessFlags accessMask) { 8421 std::string result; 8422 std::string separator; 8423 8424 if (accessMask == 0) { 8425 result = "[None]"; 8426 } else { 8427 result = "["; 8428 for (auto i = 0; i < 32; i++) { 8429 if (accessMask & (1 << i)) { 8430 result = result + separator + string_VkAccessFlagBits((VkAccessFlagBits)(1 << i)); 8431 separator = " | "; 8432 } 8433 } 8434 result = result + "]"; 8435 } 8436 return result; 8437} 8438 8439// AccessFlags MUST have 'required_bit' set, and may have one or more of 'optional_bits' set. 8440// If required_bit is zero, accessMask must have at least one of 'optional_bits' set 8441// TODO: Add tracking to ensure that at least one barrier has been set for these layout transitions 8442VkBool32 ValidateMaskBits(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask, 8443 const VkImageLayout &layout, VkAccessFlags required_bit, VkAccessFlags optional_bits, const char *type) { 8444 VkBool32 skip_call = VK_FALSE; 8445 8446 if ((accessMask & required_bit) || (!required_bit && (accessMask & optional_bits))) { 8447 if (accessMask & !(required_bit | optional_bits)) { 8448 // TODO: Verify against Valid Use 8449 skip_call |= 8450 log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8451 DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask %d %s are specified when layout is %s.", 8452 type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout)); 8453 } 8454 } else { 8455 if (!required_bit) { 8456 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8457 DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must contain at least one of access bits %d " 8458 "%s when layout is %s, unless the app has previously added a " 8459 "barrier for this transition.", 8460 type, accessMask, string_VkAccessFlags(accessMask).c_str(), optional_bits, 8461 string_VkAccessFlags(optional_bits).c_str(), string_VkImageLayout(layout)); 8462 } else { 8463 std::string opt_bits; 8464 if (optional_bits != 0) { 8465 std::stringstream ss; 8466 ss << optional_bits; 8467 opt_bits = "and may have optional bits " + ss.str() + ' ' + string_VkAccessFlags(optional_bits); 8468 } 8469 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8470 DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must have required access bit %d %s %s when " 8471 "layout is %s, unless the app has previously added a barrier for " 8472 "this transition.", 8473 type, accessMask, string_VkAccessFlags(accessMask).c_str(), required_bit, 8474 string_VkAccessFlags(required_bit).c_str(), opt_bits.c_str(), string_VkImageLayout(layout)); 8475 } 8476 } 8477 return skip_call; 8478} 8479 8480VkBool32 ValidateMaskBitsFromLayouts(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask, 8481 const VkImageLayout &layout, const char *type) { 8482 VkBool32 skip_call = VK_FALSE; 8483 switch (layout) { 8484 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: { 8485 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 8486 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, type); 8487 break; 8488 } 8489 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: { 8490 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, 8491 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, type); 8492 break; 8493 } 8494 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: { 8495 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_WRITE_BIT, 0, type); 8496 break; 8497 } 8498 case VK_IMAGE_LAYOUT_PREINITIALIZED: { 8499 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_HOST_WRITE_BIT, 0, type); 8500 break; 8501 } 8502 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: { 8503 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0, 8504 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type); 8505 break; 8506 } 8507 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: { 8508 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0, 8509 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type); 8510 break; 8511 } 8512 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: { 8513 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_READ_BIT, 0, type); 8514 break; 8515 } 8516 case VK_IMAGE_LAYOUT_UNDEFINED: { 8517 if (accessMask != 0) { 8518 // TODO: Verify against Valid Use section spec 8519 skip_call |= 8520 log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8521 DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask %d %s are specified when layout is %s.", 8522 type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout)); 8523 } 8524 break; 8525 } 8526 case VK_IMAGE_LAYOUT_GENERAL: 8527 default: { break; } 8528 } 8529 return skip_call; 8530} 8531 8532VkBool32 ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount, 8533 const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount, 8534 const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount, 8535 const VkImageMemoryBarrier *pImageMemBarriers) { 8536 VkBool32 skip_call = VK_FALSE; 8537 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 8538 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 8539 if (pCB->activeRenderPass && memBarrierCount) { 8540 if (!dev_data->renderPassMap[pCB->activeRenderPass]->hasSelfDependency[pCB->activeSubpass]) { 8541 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8542 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Barriers cannot be set during subpass %d " 8543 "with no self dependency specified.", 8544 funcName, pCB->activeSubpass); 8545 } 8546 } 8547 for (uint32_t i = 0; i < imageMemBarrierCount; ++i) { 8548 auto mem_barrier = &pImageMemBarriers[i]; 8549 auto image_data = dev_data->imageMap.find(mem_barrier->image); 8550 if (image_data != dev_data->imageMap.end()) { 8551 uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex; 8552 uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex; 8553 if (image_data->second.createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) { 8554 // srcQueueFamilyIndex and dstQueueFamilyIndex must both 8555 // be VK_QUEUE_FAMILY_IGNORED 8556 if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) { 8557 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 8558 __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS", 8559 "%s: Image Barrier for image 0x%" PRIx64 " was created with sharingMode of " 8560 "VK_SHARING_MODE_CONCURRENT. Src and dst " 8561 " queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.", 8562 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image)); 8563 } 8564 } else { 8565 // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and 8566 // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED, 8567 // or both be a valid queue family 8568 if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) && 8569 (src_q_f_index != dst_q_f_index)) { 8570 skip_call |= 8571 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8572 DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64 " was created with sharingMode " 8573 "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or " 8574 "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both " 8575 "must be.", 8576 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image)); 8577 } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) && 8578 ((src_q_f_index >= dev_data->physDevProperties.queue_family_properties.size()) || 8579 (dst_q_f_index >= dev_data->physDevProperties.queue_family_properties.size()))) { 8580 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 8581 __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS", 8582 "%s: Image 0x%" PRIx64 " was created with sharingMode " 8583 "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d" 8584 " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER 8585 "queueFamilies crated for this device.", 8586 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image), src_q_f_index, 8587 dst_q_f_index, dev_data->physDevProperties.queue_family_properties.size()); 8588 } 8589 } 8590 } 8591 8592 if (mem_barrier) { 8593 skip_call |= 8594 ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source"); 8595 skip_call |= 8596 ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest"); 8597 if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) { 8598 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8599 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image Layout cannot be transitioned to UNDEFINED or " 8600 "PREINITIALIZED.", 8601 funcName); 8602 } 8603 auto image_data = dev_data->imageMap.find(mem_barrier->image); 8604 VkFormat format; 8605 uint32_t arrayLayers, mipLevels; 8606 bool imageFound = false; 8607 if (image_data != dev_data->imageMap.end()) { 8608 format = image_data->second.createInfo.format; 8609 arrayLayers = image_data->second.createInfo.arrayLayers; 8610 mipLevels = image_data->second.createInfo.mipLevels; 8611 imageFound = true; 8612 } else if (dev_data->device_extensions.wsi_enabled) { 8613 auto imageswap_data = dev_data->device_extensions.imageToSwapchainMap.find(mem_barrier->image); 8614 if (imageswap_data != dev_data->device_extensions.imageToSwapchainMap.end()) { 8615 auto swapchain_data = dev_data->device_extensions.swapchainMap.find(imageswap_data->second); 8616 if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) { 8617 format = swapchain_data->second->createInfo.imageFormat; 8618 arrayLayers = swapchain_data->second->createInfo.imageArrayLayers; 8619 mipLevels = 1; 8620 imageFound = true; 8621 } 8622 } 8623 } 8624 if (imageFound) { 8625 if (vk_format_is_depth_and_stencil(format) && 8626 (!(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) || 8627 !(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT))) { 8628 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8629 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image is a depth and stencil format and thus must " 8630 "have both VK_IMAGE_ASPECT_DEPTH_BIT and " 8631 "VK_IMAGE_ASPECT_STENCIL_BIT set.", 8632 funcName); 8633 } 8634 int layerCount = (mem_barrier->subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS) 8635 ? 1 8636 : mem_barrier->subresourceRange.layerCount; 8637 if ((mem_barrier->subresourceRange.baseArrayLayer + layerCount) > arrayLayers) { 8638 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8639 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the " 8640 "baseArrayLayer (%d) and layerCount (%d) be less " 8641 "than or equal to the total number of layers (%d).", 8642 funcName, mem_barrier->subresourceRange.baseArrayLayer, mem_barrier->subresourceRange.layerCount, 8643 arrayLayers); 8644 } 8645 int levelCount = (mem_barrier->subresourceRange.levelCount == VK_REMAINING_MIP_LEVELS) 8646 ? 1 8647 : mem_barrier->subresourceRange.levelCount; 8648 if ((mem_barrier->subresourceRange.baseMipLevel + levelCount) > mipLevels) { 8649 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8650 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the baseMipLevel " 8651 "(%d) and levelCount (%d) be less than or equal to " 8652 "the total number of levels (%d).", 8653 funcName, mem_barrier->subresourceRange.baseMipLevel, mem_barrier->subresourceRange.levelCount, 8654 mipLevels); 8655 } 8656 } 8657 } 8658 } 8659 for (uint32_t i = 0; i < bufferBarrierCount; ++i) { 8660 auto mem_barrier = &pBufferMemBarriers[i]; 8661 if (pCB->activeRenderPass) { 8662 skip_call |= 8663 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8664 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barriers cannot be used during a render pass.", funcName); 8665 } 8666 if (!mem_barrier) 8667 continue; 8668 8669 // Validate buffer barrier queue family indices 8670 if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED && 8671 mem_barrier->srcQueueFamilyIndex >= dev_data->physDevProperties.queue_family_properties.size()) || 8672 (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED && 8673 mem_barrier->dstQueueFamilyIndex >= dev_data->physDevProperties.queue_family_properties.size())) { 8674 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8675 DRAWSTATE_INVALID_QUEUE_INDEX, "DS", 8676 "%s: Buffer Barrier 0x%" PRIx64 " has QueueFamilyIndex greater " 8677 "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.", 8678 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer), 8679 dev_data->physDevProperties.queue_family_properties.size()); 8680 } 8681 8682 auto buffer_data = dev_data->bufferMap.find(mem_barrier->buffer); 8683 uint64_t buffer_size = 8684 buffer_data->second.create_info ? reinterpret_cast<uint64_t &>(buffer_data->second.create_info->size) : 0; 8685 if (buffer_data != dev_data->bufferMap.end()) { 8686 if (mem_barrier->offset >= buffer_size) { 8687 skip_call |= 8688 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8689 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset %" PRIu64 8690 " whose sum is not less than total size %" PRIu64 ".", 8691 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer), 8692 reinterpret_cast<const uint64_t &>(mem_barrier->offset), buffer_size); 8693 } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) { 8694 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 8695 __LINE__, DRAWSTATE_INVALID_BARRIER, "DS", 8696 "%s: Buffer Barrier 0x%" PRIx64 " has offset %" PRIu64 " and size %" PRIu64 8697 " whose sum is greater than total size %" PRIu64 ".", 8698 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer), 8699 reinterpret_cast<const uint64_t &>(mem_barrier->offset), 8700 reinterpret_cast<const uint64_t &>(mem_barrier->size), buffer_size); 8701 } 8702 } 8703 } 8704 return skip_call; 8705} 8706 8707bool validateEventStageMask(VkQueue queue, uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags sourceStageMask) { 8708 bool skip_call = false; 8709 VkPipelineStageFlags stageMask = 0; 8710 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); 8711 for (uint32_t i = 0; i < eventCount; ++i) { 8712 auto queue_data = dev_data->queueMap.find(queue); 8713 if (queue_data == dev_data->queueMap.end()) 8714 return false; 8715 auto event_data = queue_data->second.eventToStageMap.find(pEvents[i]); 8716 if (event_data != queue_data->second.eventToStageMap.end()) { 8717 stageMask |= event_data->second; 8718 } else { 8719 auto global_event_data = dev_data->eventMap.find(pEvents[i]); 8720 if (global_event_data == dev_data->eventMap.end()) { 8721 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT, 8722 reinterpret_cast<const uint64_t &>(pEvents[i]), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", 8723 "Fence 0x%" PRIx64 " cannot be waited on if it has never been set.", 8724 reinterpret_cast<const uint64_t &>(pEvents[i])); 8725 } else { 8726 stageMask |= global_event_data->second.stageMask; 8727 } 8728 } 8729 } 8730 if (sourceStageMask != stageMask) { 8731 skip_call |= 8732 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8733 DRAWSTATE_INVALID_FENCE, "DS", 8734 "Submitting cmdbuffer with call to VkCmdWaitEvents using srcStageMask 0x%x which must be the bitwise OR of the " 8735 "stageMask parameters used in calls to vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if used with vkSetEvent.", 8736 sourceStageMask); 8737 } 8738 return skip_call; 8739} 8740 8741VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8742vkCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags sourceStageMask, 8743 VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, 8744 uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, 8745 uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) { 8746 VkBool32 skipCall = VK_FALSE; 8747 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8748 loader_platform_thread_lock_mutex(&globalLock); 8749 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8750 if (pCB) { 8751 for (uint32_t i = 0; i < eventCount; ++i) { 8752 pCB->waitedEvents.push_back(pEvents[i]); 8753 pCB->events.push_back(pEvents[i]); 8754 } 8755 std::function<bool(VkQueue)> eventUpdate = 8756 std::bind(validateEventStageMask, std::placeholders::_1, eventCount, pEvents, sourceStageMask); 8757 pCB->eventUpdates.push_back(eventUpdate); 8758 if (pCB->state == CB_RECORDING) { 8759 skipCall |= addCmd(dev_data, pCB, CMD_WAITEVENTS, "vkCmdWaitEvents()"); 8760 } else { 8761 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWaitEvents()"); 8762 } 8763 skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers); 8764 skipCall |= 8765 ValidateBarriers("vkCmdWaitEvents", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, 8766 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); 8767 } 8768 loader_platform_thread_unlock_mutex(&globalLock); 8769 if (VK_FALSE == skipCall) 8770 dev_data->device_dispatch_table->CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask, 8771 memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, 8772 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); 8773} 8774 8775VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8776vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, 8777 VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, 8778 uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, 8779 uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) { 8780 VkBool32 skipCall = VK_FALSE; 8781 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8782 loader_platform_thread_lock_mutex(&globalLock); 8783 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8784 if (pCB) { 8785 skipCall |= addCmd(dev_data, pCB, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()"); 8786 skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers); 8787 skipCall |= 8788 ValidateBarriers("vkCmdPipelineBarrier", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, 8789 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); 8790 } 8791 loader_platform_thread_unlock_mutex(&globalLock); 8792 if (VK_FALSE == skipCall) 8793 dev_data->device_dispatch_table->CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, 8794 memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, 8795 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); 8796} 8797 8798VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8799vkCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) { 8800 VkBool32 skipCall = VK_FALSE; 8801 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8802 loader_platform_thread_lock_mutex(&globalLock); 8803 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8804 if (pCB) { 8805 QueryObject query = {queryPool, slot}; 8806 pCB->activeQueries.insert(query); 8807 if (!pCB->startedQueries.count(query)) { 8808 pCB->startedQueries.insert(query); 8809 } 8810 skipCall |= addCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()"); 8811 } 8812 loader_platform_thread_unlock_mutex(&globalLock); 8813 if (VK_FALSE == skipCall) 8814 dev_data->device_dispatch_table->CmdBeginQuery(commandBuffer, queryPool, slot, flags); 8815} 8816 8817VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) { 8818 VkBool32 skipCall = VK_FALSE; 8819 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8820 loader_platform_thread_lock_mutex(&globalLock); 8821 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8822 if (pCB) { 8823 QueryObject query = {queryPool, slot}; 8824 if (!pCB->activeQueries.count(query)) { 8825 skipCall |= 8826 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8827 DRAWSTATE_INVALID_QUERY, "DS", "Ending a query before it was started: queryPool %" PRIu64 ", index %d", 8828 (uint64_t)(queryPool), slot); 8829 } else { 8830 pCB->activeQueries.erase(query); 8831 } 8832 pCB->queryToStateMap[query] = 1; 8833 if (pCB->state == CB_RECORDING) { 8834 skipCall |= addCmd(dev_data, pCB, CMD_ENDQUERY, "VkCmdEndQuery()"); 8835 } else { 8836 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdEndQuery()"); 8837 } 8838 } 8839 loader_platform_thread_unlock_mutex(&globalLock); 8840 if (VK_FALSE == skipCall) 8841 dev_data->device_dispatch_table->CmdEndQuery(commandBuffer, queryPool, slot); 8842} 8843 8844VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8845vkCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) { 8846 VkBool32 skipCall = VK_FALSE; 8847 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8848 loader_platform_thread_lock_mutex(&globalLock); 8849 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8850 if (pCB) { 8851 for (uint32_t i = 0; i < queryCount; i++) { 8852 QueryObject query = {queryPool, firstQuery + i}; 8853 pCB->waitedEventsBeforeQueryReset[query] = pCB->waitedEvents; 8854 pCB->queryToStateMap[query] = 0; 8855 } 8856 if (pCB->state == CB_RECORDING) { 8857 skipCall |= addCmd(dev_data, pCB, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()"); 8858 } else { 8859 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdResetQueryPool()"); 8860 } 8861 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdQueryPool"); 8862 } 8863 loader_platform_thread_unlock_mutex(&globalLock); 8864 if (VK_FALSE == skipCall) 8865 dev_data->device_dispatch_table->CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount); 8866} 8867 8868VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8869vkCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, 8870 VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) { 8871 VkBool32 skipCall = VK_FALSE; 8872 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8873 loader_platform_thread_lock_mutex(&globalLock); 8874 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8875#if MTMERGESOURCE 8876 VkDeviceMemory mem; 8877 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 8878 skipCall |= 8879 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 8880 if (cb_data != dev_data->commandBufferMap.end()) { 8881 std::function<VkBool32()> function = [=]() { 8882 set_memory_valid(dev_data, mem, true); 8883 return VK_FALSE; 8884 }; 8885 cb_data->second->validate_functions.push_back(function); 8886 } 8887 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyQueryPoolResults"); 8888 // Validate that DST buffer has correct usage flags set 8889 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, 8890 "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); 8891#endif 8892 if (pCB) { 8893 for (uint32_t i = 0; i < queryCount; i++) { 8894 QueryObject query = {queryPool, firstQuery + i}; 8895 if (!pCB->queryToStateMap[query]) { 8896 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 8897 __LINE__, DRAWSTATE_INVALID_QUERY, "DS", 8898 "Requesting a copy from query to buffer with invalid query: queryPool %" PRIu64 ", index %d", 8899 (uint64_t)(queryPool), firstQuery + i); 8900 } 8901 } 8902 if (pCB->state == CB_RECORDING) { 8903 skipCall |= addCmd(dev_data, pCB, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()"); 8904 } else { 8905 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdCopyQueryPoolResults()"); 8906 } 8907 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyQueryPoolResults"); 8908 } 8909 loader_platform_thread_unlock_mutex(&globalLock); 8910 if (VK_FALSE == skipCall) 8911 dev_data->device_dispatch_table->CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, 8912 dstOffset, stride, flags); 8913} 8914 8915VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, 8916 VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, 8917 const void *pValues) { 8918 bool skipCall = false; 8919 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8920 loader_platform_thread_lock_mutex(&globalLock); 8921 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8922 if (pCB) { 8923 if (pCB->state == CB_RECORDING) { 8924 skipCall |= addCmd(dev_data, pCB, CMD_PUSHCONSTANTS, "vkCmdPushConstants()"); 8925 } else { 8926 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdPushConstants()"); 8927 } 8928 } 8929 if ((offset + size) > dev_data->physDevProperties.properties.limits.maxPushConstantsSize) { 8930 skipCall |= validatePushConstantSize(dev_data, offset, size, "vkCmdPushConstants()"); 8931 } 8932 // TODO : Add warning if push constant update doesn't align with range 8933 loader_platform_thread_unlock_mutex(&globalLock); 8934 if (!skipCall) 8935 dev_data->device_dispatch_table->CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues); 8936} 8937 8938VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8939vkCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t slot) { 8940 VkBool32 skipCall = VK_FALSE; 8941 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8942 loader_platform_thread_lock_mutex(&globalLock); 8943 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8944 if (pCB) { 8945 QueryObject query = {queryPool, slot}; 8946 pCB->queryToStateMap[query] = 1; 8947 if (pCB->state == CB_RECORDING) { 8948 skipCall |= addCmd(dev_data, pCB, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()"); 8949 } else { 8950 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWriteTimestamp()"); 8951 } 8952 } 8953 loader_platform_thread_unlock_mutex(&globalLock); 8954 if (VK_FALSE == skipCall) 8955 dev_data->device_dispatch_table->CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot); 8956} 8957 8958VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo, 8959 const VkAllocationCallbacks *pAllocator, 8960 VkFramebuffer *pFramebuffer) { 8961 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 8962 VkResult result = dev_data->device_dispatch_table->CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer); 8963 if (VK_SUCCESS == result) { 8964 // Shadow create info and store in map 8965 VkFramebufferCreateInfo *localFBCI = new VkFramebufferCreateInfo(*pCreateInfo); 8966 if (pCreateInfo->pAttachments) { 8967 localFBCI->pAttachments = new VkImageView[localFBCI->attachmentCount]; 8968 memcpy((void *)localFBCI->pAttachments, pCreateInfo->pAttachments, localFBCI->attachmentCount * sizeof(VkImageView)); 8969 } 8970 FRAMEBUFFER_NODE fbNode = {}; 8971 fbNode.createInfo = *localFBCI; 8972 std::pair<VkFramebuffer, FRAMEBUFFER_NODE> fbPair(*pFramebuffer, fbNode); 8973 loader_platform_thread_lock_mutex(&globalLock); 8974 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { 8975 VkImageView view = pCreateInfo->pAttachments[i]; 8976 auto view_data = dev_data->imageViewMap.find(view); 8977 if (view_data == dev_data->imageViewMap.end()) { 8978 continue; 8979 } 8980 MT_FB_ATTACHMENT_INFO fb_info; 8981 get_mem_binding_from_object(dev_data, device, (uint64_t)(view_data->second.image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 8982 &fb_info.mem); 8983 fb_info.image = view_data->second.image; 8984 fbPair.second.attachments.push_back(fb_info); 8985 } 8986 dev_data->frameBufferMap.insert(fbPair); 8987 loader_platform_thread_unlock_mutex(&globalLock); 8988 } 8989 return result; 8990} 8991 8992VkBool32 FindDependency(const int index, const int dependent, const std::vector<DAGNode> &subpass_to_node, 8993 std::unordered_set<uint32_t> &processed_nodes) { 8994 // If we have already checked this node we have not found a dependency path so return false. 8995 if (processed_nodes.count(index)) 8996 return VK_FALSE; 8997 processed_nodes.insert(index); 8998 const DAGNode &node = subpass_to_node[index]; 8999 // Look for a dependency path. If one exists return true else recurse on the previous nodes. 9000 if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) { 9001 for (auto elem : node.prev) { 9002 if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) 9003 return VK_TRUE; 9004 } 9005 } else { 9006 return VK_TRUE; 9007 } 9008 return VK_FALSE; 9009} 9010 9011VkBool32 CheckDependencyExists(const layer_data *my_data, const int subpass, const std::vector<uint32_t> &dependent_subpasses, 9012 const std::vector<DAGNode> &subpass_to_node, VkBool32 &skip_call) { 9013 VkBool32 result = VK_TRUE; 9014 // Loop through all subpasses that share the same attachment and make sure a dependency exists 9015 for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) { 9016 if (subpass == dependent_subpasses[k]) 9017 continue; 9018 const DAGNode &node = subpass_to_node[subpass]; 9019 // Check for a specified dependency between the two nodes. If one exists we are done. 9020 auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]); 9021 auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]); 9022 if (prev_elem == node.prev.end() && next_elem == node.next.end()) { 9023 // If no dependency exits an implicit dependency still might. If so, warn and if not throw an error. 9024 std::unordered_set<uint32_t> processed_nodes; 9025 if (FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) || 9026 FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes)) { 9027 // TODO: Verify against Valid Use section of spec 9028 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 9029 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS", 9030 "A dependency between subpasses %d and %d must exist but only an implicit one is specified.", 9031 subpass, dependent_subpasses[k]); 9032 } else { 9033 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 9034 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS", 9035 "A dependency between subpasses %d and %d must exist but one is not specified.", subpass, 9036 dependent_subpasses[k]); 9037 result = VK_FALSE; 9038 } 9039 } 9040 } 9041 return result; 9042} 9043 9044VkBool32 CheckPreserved(const layer_data *my_data, const VkRenderPassCreateInfo *pCreateInfo, const int index, 9045 const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, VkBool32 &skip_call) { 9046 const DAGNode &node = subpass_to_node[index]; 9047 // If this node writes to the attachment return true as next nodes need to preserve the attachment. 9048 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index]; 9049 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9050 if (attachment == subpass.pColorAttachments[j].attachment) 9051 return VK_TRUE; 9052 } 9053 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { 9054 if (attachment == subpass.pDepthStencilAttachment->attachment) 9055 return VK_TRUE; 9056 } 9057 VkBool32 result = VK_FALSE; 9058 // Loop through previous nodes and see if any of them write to the attachment. 9059 for (auto elem : node.prev) { 9060 result |= CheckPreserved(my_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip_call); 9061 } 9062 // If the attachment was written to by a previous node than this node needs to preserve it. 9063 if (result && depth > 0) { 9064 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index]; 9065 VkBool32 has_preserved = VK_FALSE; 9066 for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) { 9067 if (subpass.pPreserveAttachments[j] == attachment) { 9068 has_preserved = VK_TRUE; 9069 break; 9070 } 9071 } 9072 if (has_preserved == VK_FALSE) { 9073 skip_call |= 9074 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9075 DRAWSTATE_INVALID_RENDERPASS, "DS", 9076 "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index); 9077 } 9078 } 9079 return result; 9080} 9081 9082template <class T> bool isRangeOverlapping(T offset1, T size1, T offset2, T size2) { 9083 return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) || 9084 ((offset1 > offset2) && (offset1 < (offset2 + size2))); 9085} 9086 9087bool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) { 9088 return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) && 9089 isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount)); 9090} 9091 9092VkBool32 ValidateDependencies(const layer_data *my_data, const VkRenderPassBeginInfo *pRenderPassBegin, 9093 const std::vector<DAGNode> &subpass_to_node) { 9094 VkBool32 skip_call = VK_FALSE; 9095 const VkFramebufferCreateInfo *pFramebufferInfo = &my_data->frameBufferMap.at(pRenderPassBegin->framebuffer).createInfo; 9096 const VkRenderPassCreateInfo *pCreateInfo = my_data->renderPassMap.at(pRenderPassBegin->renderPass)->pCreateInfo; 9097 std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount); 9098 std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount); 9099 std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount); 9100 // Find overlapping attachments 9101 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { 9102 for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) { 9103 VkImageView viewi = pFramebufferInfo->pAttachments[i]; 9104 VkImageView viewj = pFramebufferInfo->pAttachments[j]; 9105 if (viewi == viewj) { 9106 overlapping_attachments[i].push_back(j); 9107 overlapping_attachments[j].push_back(i); 9108 continue; 9109 } 9110 auto view_data_i = my_data->imageViewMap.find(viewi); 9111 auto view_data_j = my_data->imageViewMap.find(viewj); 9112 if (view_data_i == my_data->imageViewMap.end() || view_data_j == my_data->imageViewMap.end()) { 9113 continue; 9114 } 9115 if (view_data_i->second.image == view_data_j->second.image && 9116 isRegionOverlapping(view_data_i->second.subresourceRange, view_data_j->second.subresourceRange)) { 9117 overlapping_attachments[i].push_back(j); 9118 overlapping_attachments[j].push_back(i); 9119 continue; 9120 } 9121 auto image_data_i = my_data->imageMap.find(view_data_i->second.image); 9122 auto image_data_j = my_data->imageMap.find(view_data_j->second.image); 9123 if (image_data_i == my_data->imageMap.end() || image_data_j == my_data->imageMap.end()) { 9124 continue; 9125 } 9126 if (image_data_i->second.mem == image_data_j->second.mem && 9127 isRangeOverlapping(image_data_i->second.memOffset, image_data_i->second.memSize, image_data_j->second.memOffset, 9128 image_data_j->second.memSize)) { 9129 overlapping_attachments[i].push_back(j); 9130 overlapping_attachments[j].push_back(i); 9131 } 9132 } 9133 } 9134 for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) { 9135 uint32_t attachment = i; 9136 for (auto other_attachment : overlapping_attachments[i]) { 9137 if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) { 9138 skip_call |= 9139 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9140 DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't " 9141 "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.", 9142 attachment, other_attachment); 9143 } 9144 if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) { 9145 skip_call |= 9146 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9147 DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't " 9148 "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.", 9149 other_attachment, attachment); 9150 } 9151 } 9152 } 9153 // Find for each attachment the subpasses that use them. 9154 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9155 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; 9156 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9157 uint32_t attachment = subpass.pInputAttachments[j].attachment; 9158 input_attachment_to_subpass[attachment].push_back(i); 9159 for (auto overlapping_attachment : overlapping_attachments[attachment]) { 9160 input_attachment_to_subpass[overlapping_attachment].push_back(i); 9161 } 9162 } 9163 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9164 uint32_t attachment = subpass.pColorAttachments[j].attachment; 9165 output_attachment_to_subpass[attachment].push_back(i); 9166 for (auto overlapping_attachment : overlapping_attachments[attachment]) { 9167 output_attachment_to_subpass[overlapping_attachment].push_back(i); 9168 } 9169 } 9170 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { 9171 uint32_t attachment = subpass.pDepthStencilAttachment->attachment; 9172 output_attachment_to_subpass[attachment].push_back(i); 9173 for (auto overlapping_attachment : overlapping_attachments[attachment]) { 9174 output_attachment_to_subpass[overlapping_attachment].push_back(i); 9175 } 9176 } 9177 } 9178 // If there is a dependency needed make sure one exists 9179 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9180 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; 9181 // If the attachment is an input then all subpasses that output must have a dependency relationship 9182 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9183 const uint32_t &attachment = subpass.pInputAttachments[j].attachment; 9184 CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call); 9185 } 9186 // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship 9187 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9188 const uint32_t &attachment = subpass.pColorAttachments[j].attachment; 9189 CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call); 9190 CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call); 9191 } 9192 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { 9193 const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment; 9194 CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call); 9195 CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call); 9196 } 9197 } 9198 // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was 9199 // written. 9200 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9201 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; 9202 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9203 CheckPreserved(my_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip_call); 9204 } 9205 } 9206 return skip_call; 9207} 9208 9209VkBool32 ValidateLayouts(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo) { 9210 VkBool32 skip = VK_FALSE; 9211 9212 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9213 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; 9214 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9215 if (subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && 9216 subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 9217 if (subpass.pInputAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) { 9218 // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance 9219 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 9220 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9221 "Layout for input attachment is GENERAL but should be READ_ONLY_OPTIMAL."); 9222 } else { 9223 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9224 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9225 "Layout for input attachment is %s but can only be READ_ONLY_OPTIMAL or GENERAL.", 9226 string_VkImageLayout(subpass.pInputAttachments[j].layout)); 9227 } 9228 } 9229 } 9230 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9231 if (subpass.pColorAttachments[j].layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { 9232 if (subpass.pColorAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) { 9233 // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance 9234 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 9235 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9236 "Layout for color attachment is GENERAL but should be COLOR_ATTACHMENT_OPTIMAL."); 9237 } else { 9238 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9239 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9240 "Layout for color attachment is %s but can only be COLOR_ATTACHMENT_OPTIMAL or GENERAL.", 9241 string_VkImageLayout(subpass.pColorAttachments[j].layout)); 9242 } 9243 } 9244 } 9245 if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) { 9246 if (subpass.pDepthStencilAttachment->layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { 9247 if (subpass.pDepthStencilAttachment->layout == VK_IMAGE_LAYOUT_GENERAL) { 9248 // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance 9249 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 9250 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9251 "Layout for depth attachment is GENERAL but should be DEPTH_STENCIL_ATTACHMENT_OPTIMAL."); 9252 } else { 9253 skip |= 9254 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9255 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9256 "Layout for depth attachment is %s but can only be DEPTH_STENCIL_ATTACHMENT_OPTIMAL or GENERAL.", 9257 string_VkImageLayout(subpass.pDepthStencilAttachment->layout)); 9258 } 9259 } 9260 } 9261 } 9262 return skip; 9263} 9264 9265VkBool32 CreatePassDAG(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, 9266 std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) { 9267 VkBool32 skip_call = VK_FALSE; 9268 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9269 DAGNode &subpass_node = subpass_to_node[i]; 9270 subpass_node.pass = i; 9271 } 9272 for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) { 9273 const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i]; 9274 if (dependency.srcSubpass > dependency.dstSubpass && dependency.srcSubpass != VK_SUBPASS_EXTERNAL && 9275 dependency.dstSubpass != VK_SUBPASS_EXTERNAL) { 9276 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9277 DRAWSTATE_INVALID_RENDERPASS, "DS", 9278 "Depedency graph must be specified such that an earlier pass cannot depend on a later pass."); 9279 } else if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL && dependency.dstSubpass == VK_SUBPASS_EXTERNAL) { 9280 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9281 DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external."); 9282 } else if (dependency.srcSubpass == dependency.dstSubpass) { 9283 has_self_dependency[dependency.srcSubpass] = true; 9284 } 9285 if (dependency.dstSubpass != VK_SUBPASS_EXTERNAL) { 9286 subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass); 9287 } 9288 if (dependency.srcSubpass != VK_SUBPASS_EXTERNAL) { 9289 subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass); 9290 } 9291 } 9292 return skip_call; 9293} 9294 9295 9296VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, 9297 const VkAllocationCallbacks *pAllocator, 9298 VkShaderModule *pShaderModule) { 9299 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 9300 VkBool32 skip_call = VK_FALSE; 9301 if (!shader_is_spirv(pCreateInfo)) { 9302 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 9303 /* dev */ 0, __LINE__, SHADER_CHECKER_NON_SPIRV_SHADER, "SC", "Shader is not SPIR-V"); 9304 } 9305 9306 if (VK_FALSE != skip_call) 9307 return VK_ERROR_VALIDATION_FAILED_EXT; 9308 9309 VkResult res = my_data->device_dispatch_table->CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule); 9310 9311 if (res == VK_SUCCESS) { 9312 loader_platform_thread_lock_mutex(&globalLock); 9313 my_data->shaderModuleMap[*pShaderModule] = unique_ptr<shader_module>(new shader_module(pCreateInfo)); 9314 loader_platform_thread_unlock_mutex(&globalLock); 9315 } 9316 return res; 9317} 9318 9319VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, 9320 const VkAllocationCallbacks *pAllocator, 9321 VkRenderPass *pRenderPass) { 9322 VkBool32 skip_call = VK_FALSE; 9323 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 9324 loader_platform_thread_lock_mutex(&globalLock); 9325 // Create DAG 9326 std::vector<bool> has_self_dependency(pCreateInfo->subpassCount); 9327 std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount); 9328 skip_call |= CreatePassDAG(dev_data, device, pCreateInfo, subpass_to_node, has_self_dependency); 9329 // Validate 9330 skip_call |= ValidateLayouts(dev_data, device, pCreateInfo); 9331 if (VK_FALSE != skip_call) { 9332 return VK_ERROR_VALIDATION_FAILED_EXT; 9333 } 9334 loader_platform_thread_unlock_mutex(&globalLock); 9335 VkResult result = dev_data->device_dispatch_table->CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass); 9336 if (VK_SUCCESS == result) { 9337 loader_platform_thread_lock_mutex(&globalLock); 9338 // TODOSC : Merge in tracking of renderpass from shader_checker 9339 // Shadow create info and store in map 9340 VkRenderPassCreateInfo *localRPCI = new VkRenderPassCreateInfo(*pCreateInfo); 9341 if (pCreateInfo->pAttachments) { 9342 localRPCI->pAttachments = new VkAttachmentDescription[localRPCI->attachmentCount]; 9343 memcpy((void *)localRPCI->pAttachments, pCreateInfo->pAttachments, 9344 localRPCI->attachmentCount * sizeof(VkAttachmentDescription)); 9345 } 9346 if (pCreateInfo->pSubpasses) { 9347 localRPCI->pSubpasses = new VkSubpassDescription[localRPCI->subpassCount]; 9348 memcpy((void *)localRPCI->pSubpasses, pCreateInfo->pSubpasses, localRPCI->subpassCount * sizeof(VkSubpassDescription)); 9349 9350 for (uint32_t i = 0; i < localRPCI->subpassCount; i++) { 9351 VkSubpassDescription *subpass = (VkSubpassDescription *)&localRPCI->pSubpasses[i]; 9352 const uint32_t attachmentCount = subpass->inputAttachmentCount + 9353 subpass->colorAttachmentCount * (1 + (subpass->pResolveAttachments ? 1 : 0)) + 9354 ((subpass->pDepthStencilAttachment) ? 1 : 0) + subpass->preserveAttachmentCount; 9355 VkAttachmentReference *attachments = new VkAttachmentReference[attachmentCount]; 9356 9357 memcpy(attachments, subpass->pInputAttachments, sizeof(attachments[0]) * subpass->inputAttachmentCount); 9358 subpass->pInputAttachments = attachments; 9359 attachments += subpass->inputAttachmentCount; 9360 9361 memcpy(attachments, subpass->pColorAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount); 9362 subpass->pColorAttachments = attachments; 9363 attachments += subpass->colorAttachmentCount; 9364 9365 if (subpass->pResolveAttachments) { 9366 memcpy(attachments, subpass->pResolveAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount); 9367 subpass->pResolveAttachments = attachments; 9368 attachments += subpass->colorAttachmentCount; 9369 } 9370 9371 if (subpass->pDepthStencilAttachment) { 9372 memcpy(attachments, subpass->pDepthStencilAttachment, sizeof(attachments[0]) * 1); 9373 subpass->pDepthStencilAttachment = attachments; 9374 attachments += 1; 9375 } 9376 9377 memcpy(attachments, subpass->pPreserveAttachments, sizeof(attachments[0]) * subpass->preserveAttachmentCount); 9378 subpass->pPreserveAttachments = &attachments->attachment; 9379 } 9380 } 9381 if (pCreateInfo->pDependencies) { 9382 localRPCI->pDependencies = new VkSubpassDependency[localRPCI->dependencyCount]; 9383 memcpy((void *)localRPCI->pDependencies, pCreateInfo->pDependencies, 9384 localRPCI->dependencyCount * sizeof(VkSubpassDependency)); 9385 } 9386 dev_data->renderPassMap[*pRenderPass] = new RENDER_PASS_NODE(localRPCI); 9387 dev_data->renderPassMap[*pRenderPass]->hasSelfDependency = has_self_dependency; 9388 dev_data->renderPassMap[*pRenderPass]->subpassToNode = subpass_to_node; 9389#if MTMERGESOURCE 9390 // MTMTODO : Merge with code from above to eliminate duplication 9391 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { 9392 VkAttachmentDescription desc = pCreateInfo->pAttachments[i]; 9393 MT_PASS_ATTACHMENT_INFO pass_info; 9394 pass_info.load_op = desc.loadOp; 9395 pass_info.store_op = desc.storeOp; 9396 pass_info.attachment = i; 9397 dev_data->renderPassMap[*pRenderPass]->attachments.push_back(pass_info); 9398 } 9399 // TODO: Maybe fill list and then copy instead of locking 9400 std::unordered_map<uint32_t, bool> &attachment_first_read = dev_data->renderPassMap[*pRenderPass]->attachment_first_read; 9401 std::unordered_map<uint32_t, VkImageLayout> &attachment_first_layout = 9402 dev_data->renderPassMap[*pRenderPass]->attachment_first_layout; 9403 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9404 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; 9405 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9406 uint32_t attachment = subpass.pInputAttachments[j].attachment; 9407 if (attachment_first_read.count(attachment)) 9408 continue; 9409 attachment_first_read.insert(std::make_pair(attachment, true)); 9410 attachment_first_layout.insert(std::make_pair(attachment, subpass.pInputAttachments[j].layout)); 9411 } 9412 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9413 uint32_t attachment = subpass.pColorAttachments[j].attachment; 9414 if (attachment_first_read.count(attachment)) 9415 continue; 9416 attachment_first_read.insert(std::make_pair(attachment, false)); 9417 attachment_first_layout.insert(std::make_pair(attachment, subpass.pColorAttachments[j].layout)); 9418 } 9419 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { 9420 uint32_t attachment = subpass.pDepthStencilAttachment->attachment; 9421 if (attachment_first_read.count(attachment)) 9422 continue; 9423 attachment_first_read.insert(std::make_pair(attachment, false)); 9424 attachment_first_layout.insert(std::make_pair(attachment, subpass.pDepthStencilAttachment->layout)); 9425 } 9426 } 9427#endif 9428 loader_platform_thread_unlock_mutex(&globalLock); 9429 } 9430 return result; 9431} 9432// Free the renderpass shadow 9433static void deleteRenderPasses(layer_data *my_data) { 9434 if (my_data->renderPassMap.size() <= 0) 9435 return; 9436 for (auto ii = my_data->renderPassMap.begin(); ii != my_data->renderPassMap.end(); ++ii) { 9437 const VkRenderPassCreateInfo *pRenderPassInfo = (*ii).second->pCreateInfo; 9438 delete[] pRenderPassInfo->pAttachments; 9439 if (pRenderPassInfo->pSubpasses) { 9440 for (uint32_t i = 0; i < pRenderPassInfo->subpassCount; ++i) { 9441 // Attachements are all allocated in a block, so just need to 9442 // find the first non-null one to delete 9443 if (pRenderPassInfo->pSubpasses[i].pInputAttachments) { 9444 delete[] pRenderPassInfo->pSubpasses[i].pInputAttachments; 9445 } else if (pRenderPassInfo->pSubpasses[i].pColorAttachments) { 9446 delete[] pRenderPassInfo->pSubpasses[i].pColorAttachments; 9447 } else if (pRenderPassInfo->pSubpasses[i].pResolveAttachments) { 9448 delete[] pRenderPassInfo->pSubpasses[i].pResolveAttachments; 9449 } else if (pRenderPassInfo->pSubpasses[i].pPreserveAttachments) { 9450 delete[] pRenderPassInfo->pSubpasses[i].pPreserveAttachments; 9451 } 9452 } 9453 delete[] pRenderPassInfo->pSubpasses; 9454 } 9455 delete[] pRenderPassInfo->pDependencies; 9456 delete pRenderPassInfo; 9457 delete (*ii).second; 9458 } 9459 my_data->renderPassMap.clear(); 9460} 9461 9462VkBool32 VerifyFramebufferAndRenderPassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin) { 9463 VkBool32 skip_call = VK_FALSE; 9464 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 9465 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 9466 const VkRenderPassCreateInfo *pRenderPassInfo = dev_data->renderPassMap[pRenderPassBegin->renderPass]->pCreateInfo; 9467 const VkFramebufferCreateInfo framebufferInfo = dev_data->frameBufferMap[pRenderPassBegin->framebuffer].createInfo; 9468 if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) { 9469 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9470 DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using a framebuffer " 9471 "with a different number of attachments."); 9472 } 9473 for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) { 9474 const VkImageView &image_view = framebufferInfo.pAttachments[i]; 9475 auto image_data = dev_data->imageViewMap.find(image_view); 9476 assert(image_data != dev_data->imageViewMap.end()); 9477 const VkImage &image = image_data->second.image; 9478 const VkImageSubresourceRange &subRange = image_data->second.subresourceRange; 9479 IMAGE_CMD_BUF_LAYOUT_NODE newNode = {pRenderPassInfo->pAttachments[i].initialLayout, 9480 pRenderPassInfo->pAttachments[i].initialLayout}; 9481 // TODO: Do not iterate over every possibility - consolidate where possible 9482 for (uint32_t j = 0; j < subRange.levelCount; j++) { 9483 uint32_t level = subRange.baseMipLevel + j; 9484 for (uint32_t k = 0; k < subRange.layerCount; k++) { 9485 uint32_t layer = subRange.baseArrayLayer + k; 9486 VkImageSubresource sub = {subRange.aspectMask, level, layer}; 9487 IMAGE_CMD_BUF_LAYOUT_NODE node; 9488 if (!FindLayout(pCB, image, sub, node)) { 9489 SetLayout(pCB, image, sub, newNode); 9490 continue; 9491 } 9492 if (newNode.layout != node.layout) { 9493 skip_call |= 9494 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9495 DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using attachment %i " 9496 "where the " 9497 "intial layout differs from the starting layout.", 9498 i); 9499 } 9500 } 9501 } 9502 } 9503 return skip_call; 9504} 9505 9506void TransitionSubpassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, const int subpass_index) { 9507 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 9508 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 9509 auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass); 9510 if (render_pass_data == dev_data->renderPassMap.end()) { 9511 return; 9512 } 9513 const VkRenderPassCreateInfo *pRenderPassInfo = render_pass_data->second->pCreateInfo; 9514 auto framebuffer_data = dev_data->frameBufferMap.find(pRenderPassBegin->framebuffer); 9515 if (framebuffer_data == dev_data->frameBufferMap.end()) { 9516 return; 9517 } 9518 const VkFramebufferCreateInfo framebufferInfo = framebuffer_data->second.createInfo; 9519 const VkSubpassDescription &subpass = pRenderPassInfo->pSubpasses[subpass_index]; 9520 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9521 const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pInputAttachments[j].attachment]; 9522 SetLayout(dev_data, pCB, image_view, subpass.pInputAttachments[j].layout); 9523 } 9524 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9525 const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pColorAttachments[j].attachment]; 9526 SetLayout(dev_data, pCB, image_view, subpass.pColorAttachments[j].layout); 9527 } 9528 if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) { 9529 const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pDepthStencilAttachment->attachment]; 9530 SetLayout(dev_data, pCB, image_view, subpass.pDepthStencilAttachment->layout); 9531 } 9532} 9533 9534VkBool32 validatePrimaryCommandBuffer(const layer_data *my_data, const GLOBAL_CB_NODE *pCB, const std::string &cmd_name) { 9535 VkBool32 skip_call = VK_FALSE; 9536 if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) { 9537 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9538 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", "Cannot execute command %s on a secondary command buffer.", 9539 cmd_name.c_str()); 9540 } 9541 return skip_call; 9542} 9543 9544void TransitionFinalSubpassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin) { 9545 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 9546 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 9547 auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass); 9548 if (render_pass_data == dev_data->renderPassMap.end()) { 9549 return; 9550 } 9551 const VkRenderPassCreateInfo *pRenderPassInfo = render_pass_data->second->pCreateInfo; 9552 auto framebuffer_data = dev_data->frameBufferMap.find(pRenderPassBegin->framebuffer); 9553 if (framebuffer_data == dev_data->frameBufferMap.end()) { 9554 return; 9555 } 9556 const VkFramebufferCreateInfo framebufferInfo = framebuffer_data->second.createInfo; 9557 for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) { 9558 const VkImageView &image_view = framebufferInfo.pAttachments[i]; 9559 SetLayout(dev_data, pCB, image_view, pRenderPassInfo->pAttachments[i].finalLayout); 9560 } 9561} 9562 9563VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 9564vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, VkSubpassContents contents) { 9565 VkBool32 skipCall = VK_FALSE; 9566 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 9567 loader_platform_thread_lock_mutex(&globalLock); 9568 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 9569 if (pCB) { 9570 if (pRenderPassBegin && pRenderPassBegin->renderPass) { 9571#if MTMERGE 9572 auto pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass); 9573 if (pass_data != dev_data->renderPassMap.end()) { 9574 RENDER_PASS_NODE* pRPNode = pass_data->second; 9575 pRPNode->fb = pRenderPassBegin->framebuffer; 9576 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 9577 for (size_t i = 0; i < pRPNode->attachments.size(); ++i) { 9578 MT_FB_ATTACHMENT_INFO &fb_info = dev_data->frameBufferMap[pRPNode->fb].attachments[i]; 9579 if (pRPNode->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) { 9580 if (cb_data != dev_data->commandBufferMap.end()) { 9581 std::function<VkBool32()> function = [=]() { 9582 set_memory_valid(dev_data, fb_info.mem, true, fb_info.image); 9583 return VK_FALSE; 9584 }; 9585 cb_data->second->validate_functions.push_back(function); 9586 } 9587 VkImageLayout &attachment_layout = pRPNode->attachment_first_layout[pRPNode->attachments[i].attachment]; 9588 if (attachment_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL || 9589 attachment_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 9590 skipCall |= 9591 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 9592 VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, (uint64_t)(pRenderPassBegin->renderPass), __LINE__, 9593 MEMTRACK_INVALID_LAYOUT, "MEM", "Cannot clear attachment %d with invalid first layout %d.", 9594 pRPNode->attachments[i].attachment, attachment_layout); 9595 } 9596 } else if (pRPNode->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_DONT_CARE) { 9597 if (cb_data != dev_data->commandBufferMap.end()) { 9598 std::function<VkBool32()> function = [=]() { 9599 set_memory_valid(dev_data, fb_info.mem, false, fb_info.image); 9600 return VK_FALSE; 9601 }; 9602 cb_data->second->validate_functions.push_back(function); 9603 } 9604 } else if (pRPNode->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_LOAD) { 9605 if (cb_data != dev_data->commandBufferMap.end()) { 9606 std::function<VkBool32()> function = [=]() { 9607 return validate_memory_is_valid(dev_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image); 9608 }; 9609 cb_data->second->validate_functions.push_back(function); 9610 } 9611 } 9612 if (pRPNode->attachment_first_read[pRPNode->attachments[i].attachment]) { 9613 if (cb_data != dev_data->commandBufferMap.end()) { 9614 std::function<VkBool32()> function = [=]() { 9615 return validate_memory_is_valid(dev_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image); 9616 }; 9617 cb_data->second->validate_functions.push_back(function); 9618 } 9619 } 9620 } 9621 } 9622#endif 9623 skipCall |= VerifyFramebufferAndRenderPassLayouts(commandBuffer, pRenderPassBegin); 9624 auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass); 9625 if (render_pass_data != dev_data->renderPassMap.end()) { 9626 skipCall |= ValidateDependencies(dev_data, pRenderPassBegin, render_pass_data->second->subpassToNode); 9627 } 9628 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdBeginRenderPass"); 9629 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdBeginRenderPass"); 9630 skipCall |= addCmd(dev_data, pCB, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()"); 9631 pCB->activeRenderPass = pRenderPassBegin->renderPass; 9632 // This is a shallow copy as that is all that is needed for now 9633 pCB->activeRenderPassBeginInfo = *pRenderPassBegin; 9634 pCB->activeSubpass = 0; 9635 pCB->activeSubpassContents = contents; 9636 pCB->framebuffer = pRenderPassBegin->framebuffer; 9637 // Connect this framebuffer to this cmdBuffer 9638 dev_data->frameBufferMap[pCB->framebuffer].referencingCmdBuffers.insert(pCB->commandBuffer); 9639 } else { 9640 skipCall |= 9641 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9642 DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot use a NULL RenderPass object in vkCmdBeginRenderPass()"); 9643 } 9644 } 9645 loader_platform_thread_unlock_mutex(&globalLock); 9646 if (VK_FALSE == skipCall) { 9647 dev_data->device_dispatch_table->CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents); 9648 loader_platform_thread_lock_mutex(&globalLock); 9649 // This is a shallow copy as that is all that is needed for now 9650 dev_data->renderPassBeginInfo = *pRenderPassBegin; 9651 dev_data->currentSubpass = 0; 9652 loader_platform_thread_unlock_mutex(&globalLock); 9653 } 9654} 9655 9656VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) { 9657 VkBool32 skipCall = VK_FALSE; 9658 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 9659 loader_platform_thread_lock_mutex(&globalLock); 9660 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 9661 TransitionSubpassLayouts(commandBuffer, &dev_data->renderPassBeginInfo, ++dev_data->currentSubpass); 9662 if (pCB) { 9663 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass"); 9664 skipCall |= addCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()"); 9665 pCB->activeSubpass++; 9666 pCB->activeSubpassContents = contents; 9667 TransitionSubpassLayouts(commandBuffer, &pCB->activeRenderPassBeginInfo, pCB->activeSubpass); 9668 if (pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline) { 9669 skipCall |= validatePipelineState(dev_data, pCB, VK_PIPELINE_BIND_POINT_GRAPHICS, 9670 pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline); 9671 } 9672 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass"); 9673 } 9674 loader_platform_thread_unlock_mutex(&globalLock); 9675 if (VK_FALSE == skipCall) 9676 dev_data->device_dispatch_table->CmdNextSubpass(commandBuffer, contents); 9677} 9678 9679VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass(VkCommandBuffer commandBuffer) { 9680 VkBool32 skipCall = VK_FALSE; 9681 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 9682 loader_platform_thread_lock_mutex(&globalLock); 9683#if MTMERGESOURCE 9684 auto cb_data = dev_data->commandBufferMap.find(commandBuffer); 9685 if (cb_data != dev_data->commandBufferMap.end()) { 9686 auto pass_data = dev_data->renderPassMap.find(cb_data->second->activeRenderPass); 9687 if (pass_data != dev_data->renderPassMap.end()) { 9688 RENDER_PASS_NODE* pRPNode = pass_data->second; 9689 for (size_t i = 0; i < pRPNode->attachments.size(); ++i) { 9690 MT_FB_ATTACHMENT_INFO &fb_info = dev_data->frameBufferMap[pRPNode->fb].attachments[i]; 9691 if (pRPNode->attachments[i].store_op == VK_ATTACHMENT_STORE_OP_STORE) { 9692 if (cb_data != dev_data->commandBufferMap.end()) { 9693 std::function<VkBool32()> function = [=]() { 9694 set_memory_valid(dev_data, fb_info.mem, true, fb_info.image); 9695 return VK_FALSE; 9696 }; 9697 cb_data->second->validate_functions.push_back(function); 9698 } 9699 } else if (pRPNode->attachments[i].store_op == VK_ATTACHMENT_STORE_OP_DONT_CARE) { 9700 if (cb_data != dev_data->commandBufferMap.end()) { 9701 std::function<VkBool32()> function = [=]() { 9702 set_memory_valid(dev_data, fb_info.mem, false, fb_info.image); 9703 return VK_FALSE; 9704 }; 9705 cb_data->second->validate_functions.push_back(function); 9706 } 9707 } 9708 } 9709 } 9710 } 9711#endif 9712 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 9713 TransitionFinalSubpassLayouts(commandBuffer, &dev_data->renderPassBeginInfo); 9714 if (pCB) { 9715 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass"); 9716 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass"); 9717 skipCall |= addCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()"); 9718 TransitionFinalSubpassLayouts(commandBuffer, &pCB->activeRenderPassBeginInfo); 9719 pCB->activeRenderPass = 0; 9720 pCB->activeSubpass = 0; 9721 } 9722 loader_platform_thread_unlock_mutex(&globalLock); 9723 if (VK_FALSE == skipCall) 9724 dev_data->device_dispatch_table->CmdEndRenderPass(commandBuffer); 9725} 9726 9727bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass, 9728 VkRenderPass primaryPass, uint32_t primaryAttach, uint32_t secondaryAttach, const char *msg) { 9729 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9730 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9731 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a render pass %" PRIx64 9732 " that is not compatible with the current render pass %" PRIx64 "." 9733 "Attachment %" PRIu32 " is not compatable with %" PRIu32 ". %s", 9734 (void *)secondaryBuffer, (uint64_t)(secondaryPass), (uint64_t)(primaryPass), primaryAttach, secondaryAttach, 9735 msg); 9736} 9737 9738bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass, 9739 uint32_t primaryAttach, VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass, 9740 uint32_t secondaryAttach, bool is_multi) { 9741 bool skip_call = false; 9742 auto primary_data = dev_data->renderPassMap.find(primaryPass); 9743 auto secondary_data = dev_data->renderPassMap.find(secondaryPass); 9744 if (primary_data->second->pCreateInfo->attachmentCount <= primaryAttach) { 9745 primaryAttach = VK_ATTACHMENT_UNUSED; 9746 } 9747 if (secondary_data->second->pCreateInfo->attachmentCount <= secondaryAttach) { 9748 secondaryAttach = VK_ATTACHMENT_UNUSED; 9749 } 9750 if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) { 9751 return skip_call; 9752 } 9753 if (primaryAttach == VK_ATTACHMENT_UNUSED) { 9754 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, 9755 secondaryAttach, "The first is unused while the second is not."); 9756 return skip_call; 9757 } 9758 if (secondaryAttach == VK_ATTACHMENT_UNUSED) { 9759 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, 9760 secondaryAttach, "The second is unused while the first is not."); 9761 return skip_call; 9762 } 9763 if (primary_data->second->pCreateInfo->pAttachments[primaryAttach].format != 9764 secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].format) { 9765 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, 9766 secondaryAttach, "They have different formats."); 9767 } 9768 if (primary_data->second->pCreateInfo->pAttachments[primaryAttach].samples != 9769 secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].samples) { 9770 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, 9771 secondaryAttach, "They have different samples."); 9772 } 9773 if (is_multi && 9774 primary_data->second->pCreateInfo->pAttachments[primaryAttach].flags != 9775 secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].flags) { 9776 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, 9777 secondaryAttach, "They have different flags."); 9778 } 9779 return skip_call; 9780} 9781 9782bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass, 9783 VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass, const int subpass, bool is_multi) { 9784 bool skip_call = false; 9785 auto primary_data = dev_data->renderPassMap.find(primaryPass); 9786 auto secondary_data = dev_data->renderPassMap.find(secondaryPass); 9787 const VkSubpassDescription &primary_desc = primary_data->second->pCreateInfo->pSubpasses[subpass]; 9788 const VkSubpassDescription &secondary_desc = secondary_data->second->pCreateInfo->pSubpasses[subpass]; 9789 uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount); 9790 for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) { 9791 uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED; 9792 if (i < primary_desc.inputAttachmentCount) { 9793 primary_input_attach = primary_desc.pInputAttachments[i].attachment; 9794 } 9795 if (i < secondary_desc.inputAttachmentCount) { 9796 secondary_input_attach = secondary_desc.pInputAttachments[i].attachment; 9797 } 9798 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_input_attach, secondaryBuffer, 9799 secondaryPass, secondary_input_attach, is_multi); 9800 } 9801 uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount); 9802 for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) { 9803 uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED; 9804 if (i < primary_desc.colorAttachmentCount) { 9805 primary_color_attach = primary_desc.pColorAttachments[i].attachment; 9806 } 9807 if (i < secondary_desc.colorAttachmentCount) { 9808 secondary_color_attach = secondary_desc.pColorAttachments[i].attachment; 9809 } 9810 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_color_attach, secondaryBuffer, 9811 secondaryPass, secondary_color_attach, is_multi); 9812 uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED; 9813 if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) { 9814 primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment; 9815 } 9816 if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) { 9817 secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment; 9818 } 9819 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_resolve_attach, secondaryBuffer, 9820 secondaryPass, secondary_resolve_attach, is_multi); 9821 } 9822 uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED; 9823 if (primary_desc.pDepthStencilAttachment) { 9824 primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment; 9825 } 9826 if (secondary_desc.pDepthStencilAttachment) { 9827 secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment; 9828 } 9829 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_depthstencil_attach, secondaryBuffer, 9830 secondaryPass, secondary_depthstencil_attach, is_multi); 9831 return skip_call; 9832} 9833 9834bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass, 9835 VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass) { 9836 bool skip_call = false; 9837 // Early exit if renderPass objects are identical (and therefore compatible) 9838 if (primaryPass == secondaryPass) 9839 return skip_call; 9840 auto primary_data = dev_data->renderPassMap.find(primaryPass); 9841 auto secondary_data = dev_data->renderPassMap.find(secondaryPass); 9842 if (primary_data == dev_data->renderPassMap.end() || primary_data->second == nullptr) { 9843 skip_call |= 9844 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9845 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9846 "vkCmdExecuteCommands() called w/ invalid current Cmd Buffer %p which has invalid render pass %" PRIx64 ".", 9847 (void *)primaryBuffer, (uint64_t)(primaryPass)); 9848 return skip_call; 9849 } 9850 if (secondary_data == dev_data->renderPassMap.end() || secondary_data->second == nullptr) { 9851 skip_call |= 9852 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9853 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9854 "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer %p which has invalid render pass %" PRIx64 ".", 9855 (void *)secondaryBuffer, (uint64_t)(secondaryPass)); 9856 return skip_call; 9857 } 9858 if (primary_data->second->pCreateInfo->subpassCount != secondary_data->second->pCreateInfo->subpassCount) { 9859 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9860 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9861 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a render pass %" PRIx64 9862 " that is not compatible with the current render pass %" PRIx64 "." 9863 "They have a different number of subpasses.", 9864 (void *)secondaryBuffer, (uint64_t)(secondaryPass), (uint64_t)(primaryPass)); 9865 return skip_call; 9866 } 9867 bool is_multi = primary_data->second->pCreateInfo->subpassCount > 1; 9868 for (uint32_t i = 0; i < primary_data->second->pCreateInfo->subpassCount; ++i) { 9869 skip_call |= 9870 validateSubpassCompatibility(dev_data, primaryBuffer, primaryPass, secondaryBuffer, secondaryPass, i, is_multi); 9871 } 9872 return skip_call; 9873} 9874 9875bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB, 9876 VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) { 9877 bool skip_call = false; 9878 if (!pSubCB->beginInfo.pInheritanceInfo) { 9879 return skip_call; 9880 } 9881 VkFramebuffer primary_fb = pCB->framebuffer; 9882 VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer; 9883 if (secondary_fb != VK_NULL_HANDLE) { 9884 if (primary_fb != secondary_fb) { 9885 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9886 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9887 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a framebuffer %" PRIx64 9888 " that is not compatible with the current framebuffer %" PRIx64 ".", 9889 (void *)secondaryBuffer, (uint64_t)(secondary_fb), (uint64_t)(primary_fb)); 9890 } 9891 auto fb_data = dev_data->frameBufferMap.find(secondary_fb); 9892 if (fb_data == dev_data->frameBufferMap.end()) { 9893 skip_call |= 9894 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9895 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p " 9896 "which has invalid framebuffer %" PRIx64 ".", 9897 (void *)secondaryBuffer, (uint64_t)(secondary_fb)); 9898 return skip_call; 9899 } 9900 skip_call |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb_data->second.createInfo.renderPass, 9901 secondaryBuffer, pSubCB->beginInfo.pInheritanceInfo->renderPass); 9902 } 9903 return skip_call; 9904} 9905 9906bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) { 9907 bool skipCall = false; 9908 unordered_set<int> activeTypes; 9909 for (auto queryObject : pCB->activeQueries) { 9910 auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool); 9911 if (queryPoolData != dev_data->queryPoolMap.end()) { 9912 if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS && 9913 pSubCB->beginInfo.pInheritanceInfo) { 9914 VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics; 9915 if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) { 9916 skipCall |= log_msg( 9917 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9918 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9919 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p " 9920 "which has invalid active query pool %" PRIx64 ". Pipeline statistics is being queried so the command " 9921 "buffer must have all bits set on the queryPool.", 9922 reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first)); 9923 } 9924 } 9925 activeTypes.insert(queryPoolData->second.createInfo.queryType); 9926 } 9927 } 9928 for (auto queryObject : pSubCB->startedQueries) { 9929 auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool); 9930 if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) { 9931 skipCall |= 9932 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9933 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9934 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p " 9935 "which has invalid active query pool %" PRIx64 "of type %d but a query of that type has been started on " 9936 "secondary Cmd Buffer %p.", 9937 reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first), 9938 queryPoolData->second.createInfo.queryType, reinterpret_cast<void *>(pSubCB->commandBuffer)); 9939 } 9940 } 9941 return skipCall; 9942} 9943 9944VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 9945vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount, const VkCommandBuffer *pCommandBuffers) { 9946 VkBool32 skipCall = VK_FALSE; 9947 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 9948 loader_platform_thread_lock_mutex(&globalLock); 9949 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 9950 if (pCB) { 9951 GLOBAL_CB_NODE *pSubCB = NULL; 9952 for (uint32_t i = 0; i < commandBuffersCount; i++) { 9953 pSubCB = getCBNode(dev_data, pCommandBuffers[i]); 9954 if (!pSubCB) { 9955 skipCall |= 9956 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9957 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9958 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p in element %u of pCommandBuffers array.", 9959 (void *)pCommandBuffers[i], i); 9960 } else if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) { 9961 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 9962 __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9963 "vkCmdExecuteCommands() called w/ Primary Cmd Buffer %p in element %u of pCommandBuffers " 9964 "array. All cmd buffers in pCommandBuffers array must be secondary.", 9965 (void *)pCommandBuffers[i], i); 9966 } else if (pCB->activeRenderPass) { // Secondary CB w/i RenderPass must have *CONTINUE_BIT set 9967 if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) { 9968 skipCall |= log_msg( 9969 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 9970 (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 9971 "vkCmdExecuteCommands(): Secondary Command Buffer (%p) executed within render pass (%#" PRIxLEAST64 9972 ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set.", 9973 (void *)pCommandBuffers[i], (uint64_t)pCB->activeRenderPass); 9974 } else { 9975 // Make sure render pass is compatible with parent command buffer pass if has continue 9976 skipCall |= validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass, pCommandBuffers[i], 9977 pSubCB->beginInfo.pInheritanceInfo->renderPass); 9978 skipCall |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB); 9979 } 9980 string errorString = ""; 9981 if (!verify_renderpass_compatibility(dev_data, pCB->activeRenderPass, 9982 pSubCB->beginInfo.pInheritanceInfo->renderPass, errorString)) { 9983 skipCall |= log_msg( 9984 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 9985 (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS", 9986 "vkCmdExecuteCommands(): Secondary Command Buffer (%p) w/ render pass (%#" PRIxLEAST64 9987 ") is incompatible w/ primary command buffer (%p) w/ render pass (%#" PRIxLEAST64 ") due to: %s", 9988 (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->renderPass, (void *)commandBuffer, 9989 (uint64_t)pCB->activeRenderPass, errorString.c_str()); 9990 } 9991 // If framebuffer for secondary CB is not NULL, then it must match FB from vkCmdBeginRenderPass() 9992 // that this CB will be executed in AND framebuffer must have been created w/ RP compatible w/ renderpass 9993 if (pSubCB->beginInfo.pInheritanceInfo->framebuffer) { 9994 if (pSubCB->beginInfo.pInheritanceInfo->framebuffer != pCB->activeRenderPassBeginInfo.framebuffer) { 9995 skipCall |= log_msg( 9996 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 9997 (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_FRAMEBUFFER_INCOMPATIBLE, "DS", 9998 "vkCmdExecuteCommands(): Secondary Command Buffer (%p) references framebuffer (%#" PRIxLEAST64 9999 ") that does not match framebuffer (%#" PRIxLEAST64 ") in active renderpass (%#" PRIxLEAST64 ").", 10000 (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->framebuffer, 10001 (uint64_t)pCB->activeRenderPassBeginInfo.framebuffer, (uint64_t)pCB->activeRenderPass); 10002 } 10003 } 10004 } 10005 // TODO(mlentine): Move more logic into this method 10006 skipCall |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB); 10007 skipCall |= validateCommandBufferState(dev_data, pSubCB); 10008 // Secondary cmdBuffers are considered pending execution starting w/ 10009 // being recorded 10010 if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) { 10011 if (dev_data->globalInFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->globalInFlightCmdBuffers.end()) { 10012 skipCall |= log_msg( 10013 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 10014 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS", 10015 "Attempt to simultaneously execute CB %#" PRIxLEAST64 " w/o VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT " 10016 "set!", 10017 (uint64_t)(pCB->commandBuffer)); 10018 } 10019 if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) { 10020 // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous 10021 skipCall |= log_msg( 10022 dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 10023 (uint64_t)(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS", 10024 "vkCmdExecuteCommands(): Secondary Command Buffer (%#" PRIxLEAST64 10025 ") does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer " 10026 "(%#" PRIxLEAST64 ") to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT " 10027 "set, even though it does.", 10028 (uint64_t)(pCommandBuffers[i]), (uint64_t)(pCB->commandBuffer)); 10029 pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; 10030 } 10031 } 10032 if (!pCB->activeQueries.empty() && !dev_data->physDevProperties.features.inheritedQueries) { 10033 skipCall |= 10034 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 10035 reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 10036 "vkCmdExecuteCommands(): Secondary Command Buffer " 10037 "(%#" PRIxLEAST64 ") cannot be submitted with a query in " 10038 "flight and inherited queries not " 10039 "supported on this device.", 10040 reinterpret_cast<uint64_t>(pCommandBuffers[i])); 10041 } 10042 pSubCB->primaryCommandBuffer = pCB->commandBuffer; 10043 pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer); 10044 dev_data->globalInFlightCmdBuffers.insert(pSubCB->commandBuffer); 10045 } 10046 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteComands"); 10047 skipCall |= addCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteComands()"); 10048 } 10049 loader_platform_thread_unlock_mutex(&globalLock); 10050 if (VK_FALSE == skipCall) 10051 dev_data->device_dispatch_table->CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers); 10052} 10053 10054VkBool32 ValidateMapImageLayouts(VkDevice device, VkDeviceMemory mem) { 10055 VkBool32 skip_call = VK_FALSE; 10056 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10057 auto mem_data = dev_data->memObjMap.find(mem); 10058 if ((mem_data != dev_data->memObjMap.end()) && (mem_data->second.image != VK_NULL_HANDLE)) { 10059 std::vector<VkImageLayout> layouts; 10060 if (FindLayouts(dev_data, mem_data->second.image, layouts)) { 10061 for (auto layout : layouts) { 10062 if (layout != VK_IMAGE_LAYOUT_PREINITIALIZED && layout != VK_IMAGE_LAYOUT_GENERAL) { 10063 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 10064 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot map an image with layout %s. Only " 10065 "GENERAL or PREINITIALIZED are supported.", 10066 string_VkImageLayout(layout)); 10067 } 10068 } 10069 } 10070 } 10071 return skip_call; 10072} 10073 10074VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 10075vkMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags, void **ppData) { 10076 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10077 10078 VkBool32 skip_call = VK_FALSE; 10079 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10080 loader_platform_thread_lock_mutex(&globalLock); 10081#if MTMERGESOURCE 10082 DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem); 10083 if (pMemObj) { 10084 pMemObj->valid = true; 10085 if ((memProps.memoryTypes[pMemObj->allocInfo.memoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) { 10086 skip_call = 10087 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 10088 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_STATE, "MEM", 10089 "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj %#" PRIxLEAST64, (uint64_t)mem); 10090 } 10091 } 10092 skip_call |= validateMemRange(dev_data, mem, offset, size); 10093 storeMemRanges(dev_data, mem, offset, size); 10094#endif 10095 skip_call |= ValidateMapImageLayouts(device, mem); 10096 loader_platform_thread_unlock_mutex(&globalLock); 10097 10098 if (VK_FALSE == skip_call) { 10099 result = dev_data->device_dispatch_table->MapMemory(device, mem, offset, size, flags, ppData); 10100#if MTMERGESOURCE 10101 initializeAndTrackMemory(dev_data, mem, size, ppData); 10102#endif 10103 } 10104 return result; 10105} 10106 10107#if MTMERGESOURCE 10108VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(VkDevice device, VkDeviceMemory mem) { 10109 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10110 VkBool32 skipCall = VK_FALSE; 10111 10112 loader_platform_thread_lock_mutex(&globalLock); 10113 skipCall |= deleteMemRanges(my_data, mem); 10114 loader_platform_thread_unlock_mutex(&globalLock); 10115 if (VK_FALSE == skipCall) { 10116 my_data->device_dispatch_table->UnmapMemory(device, mem); 10117 } 10118} 10119 10120VkBool32 validateMemoryIsMapped(layer_data *my_data, const char *funcName, uint32_t memRangeCount, 10121 const VkMappedMemoryRange *pMemRanges) { 10122 VkBool32 skipCall = VK_FALSE; 10123 for (uint32_t i = 0; i < memRangeCount; ++i) { 10124 auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory); 10125 if (mem_element != my_data->memObjMap.end()) { 10126 if (mem_element->second.memRange.offset > pMemRanges[i].offset) { 10127 skipCall |= log_msg( 10128 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 10129 (uint64_t)pMemRanges[i].memory, __LINE__, MEMTRACK_INVALID_MAP, "MEM", 10130 "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER ") is less than Memory Object's offset " 10131 "(" PRINTF_SIZE_T_SPECIFIER ").", 10132 funcName, static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(mem_element->second.memRange.offset)); 10133 } 10134 if ((mem_element->second.memRange.size != VK_WHOLE_SIZE) && 10135 ((mem_element->second.memRange.offset + mem_element->second.memRange.size) < 10136 (pMemRanges[i].offset + pMemRanges[i].size))) { 10137 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 10138 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__, 10139 MEMTRACK_INVALID_MAP, "MEM", "%s: Flush/Invalidate upper-bound (" PRINTF_SIZE_T_SPECIFIER 10140 ") exceeds the Memory Object's upper-bound " 10141 "(" PRINTF_SIZE_T_SPECIFIER ").", 10142 funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size), 10143 static_cast<size_t>(mem_element->second.memRange.offset + mem_element->second.memRange.size)); 10144 } 10145 } 10146 } 10147 return skipCall; 10148} 10149 10150VkBool32 validateAndCopyNoncoherentMemoryToDriver(layer_data *my_data, uint32_t memRangeCount, 10151 const VkMappedMemoryRange *pMemRanges) { 10152 VkBool32 skipCall = VK_FALSE; 10153 for (uint32_t i = 0; i < memRangeCount; ++i) { 10154 auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory); 10155 if (mem_element != my_data->memObjMap.end()) { 10156 if (mem_element->second.pData) { 10157 VkDeviceSize size = mem_element->second.memRange.size; 10158 VkDeviceSize half_size = (size / 2); 10159 char *data = static_cast<char *>(mem_element->second.pData); 10160 for (auto j = 0; j < half_size; ++j) { 10161 if (data[j] != NoncoherentMemoryFillValue) { 10162 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 10163 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__, 10164 MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj %" PRIxLEAST64, 10165 (uint64_t)pMemRanges[i].memory); 10166 } 10167 } 10168 for (auto j = size + half_size; j < 2 * size; ++j) { 10169 if (data[j] != NoncoherentMemoryFillValue) { 10170 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 10171 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__, 10172 MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj %" PRIxLEAST64, 10173 (uint64_t)pMemRanges[i].memory); 10174 } 10175 } 10176 memcpy(mem_element->second.pDriverData, static_cast<void *>(data + (size_t)(half_size)), (size_t)(size)); 10177 } 10178 } 10179 } 10180 return skipCall; 10181} 10182 10183VK_LAYER_EXPORT VkResult VKAPI_CALL 10184vkFlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) { 10185 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10186 VkBool32 skipCall = VK_FALSE; 10187 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10188 10189 loader_platform_thread_lock_mutex(&globalLock); 10190 skipCall |= validateAndCopyNoncoherentMemoryToDriver(my_data, memRangeCount, pMemRanges); 10191 skipCall |= validateMemoryIsMapped(my_data, "vkFlushMappedMemoryRanges", memRangeCount, pMemRanges); 10192 loader_platform_thread_unlock_mutex(&globalLock); 10193 if (VK_FALSE == skipCall) { 10194 result = my_data->device_dispatch_table->FlushMappedMemoryRanges(device, memRangeCount, pMemRanges); 10195 } 10196 return result; 10197} 10198 10199VK_LAYER_EXPORT VkResult VKAPI_CALL 10200vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) { 10201 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10202 VkBool32 skipCall = VK_FALSE; 10203 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10204 10205 loader_platform_thread_lock_mutex(&globalLock); 10206 skipCall |= validateMemoryIsMapped(my_data, "vkInvalidateMappedMemoryRanges", memRangeCount, pMemRanges); 10207 loader_platform_thread_unlock_mutex(&globalLock); 10208 if (VK_FALSE == skipCall) { 10209 result = my_data->device_dispatch_table->InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges); 10210 } 10211 return result; 10212} 10213#endif 10214 10215VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) { 10216 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10217 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10218 VkBool32 skipCall = VK_FALSE; 10219#if MTMERGESOURCE 10220 loader_platform_thread_lock_mutex(&globalLock); 10221 // Track objects tied to memory 10222 uint64_t image_handle = (uint64_t)(image); 10223 skipCall = 10224 set_mem_binding(dev_data, device, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory"); 10225 add_object_binding_info(dev_data, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, mem); 10226 { 10227 VkMemoryRequirements memRequirements; 10228 vkGetImageMemoryRequirements(device, image, &memRequirements); 10229 skipCall |= validate_buffer_image_aliasing(dev_data, image_handle, mem, memoryOffset, memRequirements, 10230 dev_data->memObjMap[mem].imageRanges, dev_data->memObjMap[mem].bufferRanges, 10231 VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); 10232 } 10233 print_mem_list(dev_data, device); 10234 loader_platform_thread_unlock_mutex(&globalLock); 10235#endif 10236 if (VK_FALSE == skipCall) { 10237 result = dev_data->device_dispatch_table->BindImageMemory(device, image, mem, memoryOffset); 10238 VkMemoryRequirements memRequirements; 10239 dev_data->device_dispatch_table->GetImageMemoryRequirements(device, image, &memRequirements); 10240 loader_platform_thread_lock_mutex(&globalLock); 10241 dev_data->memObjMap[mem].image = image; 10242 dev_data->imageMap[image].mem = mem; 10243 dev_data->imageMap[image].memOffset = memoryOffset; 10244 dev_data->imageMap[image].memSize = memRequirements.size; 10245 loader_platform_thread_unlock_mutex(&globalLock); 10246 } 10247 return result; 10248} 10249 10250VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent(VkDevice device, VkEvent event) { 10251 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10252 loader_platform_thread_lock_mutex(&globalLock); 10253 dev_data->eventMap[event].needsSignaled = false; 10254 dev_data->eventMap[event].stageMask = VK_PIPELINE_STAGE_HOST_BIT; 10255 loader_platform_thread_unlock_mutex(&globalLock); 10256 VkResult result = dev_data->device_dispatch_table->SetEvent(device, event); 10257 return result; 10258} 10259 10260VKAPI_ATTR VkResult VKAPI_CALL 10261vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence) { 10262 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); 10263 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10264 VkBool32 skip_call = VK_FALSE; 10265#if MTMERGESOURCE 10266 //MTMTODO : Merge this code with the checks below 10267 loader_platform_thread_lock_mutex(&globalLock); 10268 10269 for (uint32_t i = 0; i < bindInfoCount; i++) { 10270 const VkBindSparseInfo *bindInfo = &pBindInfo[i]; 10271 // Track objects tied to memory 10272 for (uint32_t j = 0; j < bindInfo->bufferBindCount; j++) { 10273 for (uint32_t k = 0; k < bindInfo->pBufferBinds[j].bindCount; k++) { 10274 if (set_sparse_mem_binding(dev_data, queue, bindInfo->pBufferBinds[j].pBinds[k].memory, 10275 (uint64_t)bindInfo->pBufferBinds[j].buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, 10276 "vkQueueBindSparse")) 10277 skip_call = VK_TRUE; 10278 } 10279 } 10280 for (uint32_t j = 0; j < bindInfo->imageOpaqueBindCount; j++) { 10281 for (uint32_t k = 0; k < bindInfo->pImageOpaqueBinds[j].bindCount; k++) { 10282 if (set_sparse_mem_binding(dev_data, queue, bindInfo->pImageOpaqueBinds[j].pBinds[k].memory, 10283 (uint64_t)bindInfo->pImageOpaqueBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 10284 "vkQueueBindSparse")) 10285 skip_call = VK_TRUE; 10286 } 10287 } 10288 for (uint32_t j = 0; j < bindInfo->imageBindCount; j++) { 10289 for (uint32_t k = 0; k < bindInfo->pImageBinds[j].bindCount; k++) { 10290 if (set_sparse_mem_binding(dev_data, queue, bindInfo->pImageBinds[j].pBinds[k].memory, 10291 (uint64_t)bindInfo->pImageBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 10292 "vkQueueBindSparse")) 10293 skip_call = VK_TRUE; 10294 } 10295 } 10296 // Validate semaphore state 10297 for (uint32_t i = 0; i < bindInfo->waitSemaphoreCount; i++) { 10298 VkSemaphore sem = bindInfo->pWaitSemaphores[i]; 10299 10300 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 10301 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_SIGNALLED) { 10302 skip_call = 10303 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, 10304 (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE", 10305 "vkQueueBindSparse: Semaphore must be in signaled state before passing to pWaitSemaphores"); 10306 } 10307 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_WAIT; 10308 } 10309 } 10310 for (uint32_t i = 0; i < bindInfo->signalSemaphoreCount; i++) { 10311 VkSemaphore sem = bindInfo->pSignalSemaphores[i]; 10312 10313 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 10314 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_UNSET) { 10315 skip_call = 10316 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, 10317 (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE", 10318 "vkQueueBindSparse: Semaphore must not be currently signaled or in a wait state"); 10319 } 10320 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_SIGNALLED; 10321 } 10322 } 10323 } 10324 10325 print_mem_list(dev_data, queue); 10326 loader_platform_thread_unlock_mutex(&globalLock); 10327#endif 10328 loader_platform_thread_lock_mutex(&globalLock); 10329 for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) { 10330 const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx]; 10331 for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) { 10332 if (dev_data->semaphoreMap[bindInfo.pWaitSemaphores[i]].signaled) { 10333 dev_data->semaphoreMap[bindInfo.pWaitSemaphores[i]].signaled = 0; 10334 } else { 10335 skip_call |= 10336 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 10337 __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS", 10338 "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.", 10339 (uint64_t)(queue), (uint64_t)(bindInfo.pWaitSemaphores[i])); 10340 } 10341 } 10342 for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) { 10343 dev_data->semaphoreMap[bindInfo.pSignalSemaphores[i]].signaled = 1; 10344 } 10345 } 10346 loader_platform_thread_unlock_mutex(&globalLock); 10347 10348 if (VK_FALSE == skip_call) 10349 return dev_data->device_dispatch_table->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence); 10350#if MTMERGESOURCE 10351 // Update semaphore state 10352 loader_platform_thread_lock_mutex(&globalLock); 10353 for (uint32_t bind_info_idx = 0; bind_info_idx < bindInfoCount; bind_info_idx++) { 10354 const VkBindSparseInfo *bindInfo = &pBindInfo[bind_info_idx]; 10355 for (uint32_t i = 0; i < bindInfo->waitSemaphoreCount; i++) { 10356 VkSemaphore sem = bindInfo->pWaitSemaphores[i]; 10357 10358 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 10359 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_UNSET; 10360 } 10361 } 10362 } 10363 loader_platform_thread_unlock_mutex(&globalLock); 10364#endif 10365 10366 return result; 10367} 10368 10369VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, 10370 const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) { 10371 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10372 VkResult result = dev_data->device_dispatch_table->CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore); 10373 if (result == VK_SUCCESS) { 10374 loader_platform_thread_lock_mutex(&globalLock); 10375 SEMAPHORE_NODE* sNode = &dev_data->semaphoreMap[*pSemaphore]; 10376 sNode->signaled = 0; 10377 sNode->queue = VK_NULL_HANDLE; 10378 sNode->in_use.store(0); 10379 sNode->state = MEMTRACK_SEMAPHORE_STATE_UNSET; 10380 loader_platform_thread_unlock_mutex(&globalLock); 10381 } 10382 return result; 10383} 10384 10385VKAPI_ATTR VkResult VKAPI_CALL 10386vkCreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) { 10387 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10388 VkResult result = dev_data->device_dispatch_table->CreateEvent(device, pCreateInfo, pAllocator, pEvent); 10389 if (result == VK_SUCCESS) { 10390 loader_platform_thread_lock_mutex(&globalLock); 10391 dev_data->eventMap[*pEvent].needsSignaled = false; 10392 dev_data->eventMap[*pEvent].in_use.store(0); 10393 dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0); 10394 loader_platform_thread_unlock_mutex(&globalLock); 10395 } 10396 return result; 10397} 10398 10399VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, 10400 const VkAllocationCallbacks *pAllocator, 10401 VkSwapchainKHR *pSwapchain) { 10402 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10403 VkResult result = dev_data->device_dispatch_table->CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); 10404 10405 if (VK_SUCCESS == result) { 10406 SWAPCHAIN_NODE *psc_node = new SWAPCHAIN_NODE(pCreateInfo); 10407 loader_platform_thread_lock_mutex(&globalLock); 10408 dev_data->device_extensions.swapchainMap[*pSwapchain] = psc_node; 10409 loader_platform_thread_unlock_mutex(&globalLock); 10410 } 10411 10412 return result; 10413} 10414 10415VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 10416vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) { 10417 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10418 bool skipCall = false; 10419 10420 loader_platform_thread_lock_mutex(&globalLock); 10421 auto swapchain_data = dev_data->device_extensions.swapchainMap.find(swapchain); 10422 if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) { 10423 if (swapchain_data->second->images.size() > 0) { 10424 for (auto swapchain_image : swapchain_data->second->images) { 10425 auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image); 10426 if (image_sub != dev_data->imageSubresourceMap.end()) { 10427 for (auto imgsubpair : image_sub->second) { 10428 auto image_item = dev_data->imageLayoutMap.find(imgsubpair); 10429 if (image_item != dev_data->imageLayoutMap.end()) { 10430 dev_data->imageLayoutMap.erase(image_item); 10431 } 10432 } 10433 dev_data->imageSubresourceMap.erase(image_sub); 10434 } 10435#if MTMERGESOURCE 10436 skipCall = clear_object_binding(dev_data, device, (uint64_t)swapchain_image, 10437 VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT); 10438 dev_data->imageBindingMap.erase((uint64_t)swapchain_image); 10439#endif 10440 } 10441 } 10442 delete swapchain_data->second; 10443 dev_data->device_extensions.swapchainMap.erase(swapchain); 10444 } 10445 loader_platform_thread_unlock_mutex(&globalLock); 10446 if (!skipCall) 10447 dev_data->device_dispatch_table->DestroySwapchainKHR(device, swapchain, pAllocator); 10448} 10449 10450VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 10451vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount, VkImage *pSwapchainImages) { 10452 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10453 VkResult result = dev_data->device_dispatch_table->GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages); 10454 10455 if (result == VK_SUCCESS && pSwapchainImages != NULL) { 10456 // This should never happen and is checked by param checker. 10457 if (!pCount) 10458 return result; 10459 loader_platform_thread_lock_mutex(&globalLock); 10460 const size_t count = *pCount; 10461 auto swapchain_node = dev_data->device_extensions.swapchainMap[swapchain]; 10462 if (!swapchain_node->images.empty()) { 10463 // TODO : Not sure I like the memcmp here, but it works 10464 const bool mismatch = (swapchain_node->images.size() != count || 10465 memcmp(&swapchain_node->images[0], pSwapchainImages, sizeof(swapchain_node->images[0]) * count)); 10466 if (mismatch) { 10467 // TODO: Verify against Valid Usage section of extension 10468 log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, 10469 (uint64_t)swapchain, __LINE__, MEMTRACK_NONE, "SWAP_CHAIN", 10470 "vkGetSwapchainInfoKHR(%" PRIu64 10471 ", VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR) returned mismatching data", 10472 (uint64_t)(swapchain)); 10473 } 10474 } 10475 for (uint32_t i = 0; i < *pCount; ++i) { 10476 IMAGE_LAYOUT_NODE image_layout_node; 10477 image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED; 10478 image_layout_node.format = swapchain_node->createInfo.imageFormat; 10479 dev_data->imageMap[pSwapchainImages[i]].createInfo.mipLevels = 1; 10480 dev_data->imageMap[pSwapchainImages[i]].createInfo.arrayLayers = swapchain_node->createInfo.imageArrayLayers; 10481 swapchain_node->images.push_back(pSwapchainImages[i]); 10482 ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()}; 10483 dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair); 10484 dev_data->imageLayoutMap[subpair] = image_layout_node; 10485 dev_data->device_extensions.imageToSwapchainMap[pSwapchainImages[i]] = swapchain; 10486 } 10487 if (!swapchain_node->images.empty()) { 10488 for (auto image : swapchain_node->images) { 10489 // Add image object binding, then insert the new Mem Object and then bind it to created image 10490#if MTMERGESOURCE 10491 add_object_create_info(dev_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, 10492 &swapchain_node->createInfo); 10493#endif 10494 } 10495 } 10496 loader_platform_thread_unlock_mutex(&globalLock); 10497 } 10498 return result; 10499} 10500 10501VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) { 10502 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); 10503 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10504 bool skip_call = false; 10505 10506 if (pPresentInfo) { 10507 loader_platform_thread_lock_mutex(&globalLock); 10508 for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) { 10509 if (dev_data->semaphoreMap[pPresentInfo->pWaitSemaphores[i]].signaled) { 10510 dev_data->semaphoreMap[pPresentInfo->pWaitSemaphores[i]].signaled = 0; 10511 } else { 10512 skip_call |= 10513 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 10514 __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS", 10515 "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.", 10516 (uint64_t)(queue), (uint64_t)(pPresentInfo->pWaitSemaphores[i])); 10517 } 10518 } 10519 VkDeviceMemory mem; 10520 for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) { 10521 auto swapchain_data = dev_data->device_extensions.swapchainMap.find(pPresentInfo->pSwapchains[i]); 10522 if (swapchain_data != dev_data->device_extensions.swapchainMap.end() && 10523 pPresentInfo->pImageIndices[i] < swapchain_data->second->images.size()) { 10524 VkImage image = swapchain_data->second->images[pPresentInfo->pImageIndices[i]]; 10525#if MTMERGESOURCE 10526 skip_call |= 10527 get_mem_binding_from_object(dev_data, queue, (uint64_t)(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 10528 skip_call |= validate_memory_is_valid(dev_data, mem, "vkQueuePresentKHR()", image); 10529#endif 10530 vector<VkImageLayout> layouts; 10531 if (FindLayouts(dev_data, image, layouts)) { 10532 for (auto layout : layouts) { 10533 if (layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { 10534 skip_call |= 10535 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, 10536 reinterpret_cast<uint64_t &>(queue), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 10537 "Images passed to present must be in layout " 10538 "PRESENT_SOURCE_KHR but is in %s", 10539 string_VkImageLayout(layout)); 10540 } 10541 } 10542 } 10543 } 10544 } 10545 loader_platform_thread_unlock_mutex(&globalLock); 10546 } 10547 10548 if (!skip_call) 10549 result = dev_data->device_dispatch_table->QueuePresentKHR(queue, pPresentInfo); 10550#if MTMERGESOURCE 10551 loader_platform_thread_lock_mutex(&globalLock); 10552 for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; i++) { 10553 VkSemaphore sem = pPresentInfo->pWaitSemaphores[i]; 10554 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 10555 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_UNSET; 10556 } 10557 } 10558 loader_platform_thread_unlock_mutex(&globalLock); 10559#endif 10560 return result; 10561} 10562 10563VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, 10564 VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) { 10565 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10566 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10567 bool skipCall = false; 10568#if MTMERGESOURCE 10569 loader_platform_thread_lock_mutex(&globalLock); 10570 if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) { 10571 if (dev_data->semaphoreMap[semaphore].state != MEMTRACK_SEMAPHORE_STATE_UNSET) { 10572 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, 10573 (uint64_t)semaphore, __LINE__, MEMTRACK_NONE, "SEMAPHORE", 10574 "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state"); 10575 } 10576 dev_data->semaphoreMap[semaphore].state = MEMTRACK_SEMAPHORE_STATE_SIGNALLED; 10577 } 10578 auto fence_data = dev_data->fenceMap.find(fence); 10579 if (fence_data != dev_data->fenceMap.end()) { 10580 fence_data->second.swapchain = swapchain; 10581 } 10582 loader_platform_thread_unlock_mutex(&globalLock); 10583#endif 10584 if (!skipCall) { 10585 result = 10586 dev_data->device_dispatch_table->AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex); 10587 } 10588 loader_platform_thread_lock_mutex(&globalLock); 10589 // FIXME/TODO: Need to add some thing code the "fence" parameter 10590 dev_data->semaphoreMap[semaphore].signaled = 1; 10591 loader_platform_thread_unlock_mutex(&globalLock); 10592 return result; 10593} 10594 10595VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 10596vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, 10597 const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) { 10598 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); 10599 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; 10600 VkResult res = pTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback); 10601 if (VK_SUCCESS == res) { 10602 loader_platform_thread_lock_mutex(&globalLock); 10603 res = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pMsgCallback); 10604 loader_platform_thread_unlock_mutex(&globalLock); 10605 } 10606 return res; 10607} 10608 10609VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, 10610 VkDebugReportCallbackEXT msgCallback, 10611 const VkAllocationCallbacks *pAllocator) { 10612 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); 10613 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; 10614 pTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator); 10615 loader_platform_thread_lock_mutex(&globalLock); 10616 layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator); 10617 loader_platform_thread_unlock_mutex(&globalLock); 10618} 10619 10620VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 10621vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object, 10622 size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) { 10623 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); 10624 my_data->instance_dispatch_table->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, 10625 pMsg); 10626} 10627 10628VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) { 10629 if (!strcmp(funcName, "vkGetDeviceProcAddr")) 10630 return (PFN_vkVoidFunction)vkGetDeviceProcAddr; 10631 if (!strcmp(funcName, "vkDestroyDevice")) 10632 return (PFN_vkVoidFunction)vkDestroyDevice; 10633 if (!strcmp(funcName, "vkQueueSubmit")) 10634 return (PFN_vkVoidFunction)vkQueueSubmit; 10635 if (!strcmp(funcName, "vkWaitForFences")) 10636 return (PFN_vkVoidFunction)vkWaitForFences; 10637 if (!strcmp(funcName, "vkGetFenceStatus")) 10638 return (PFN_vkVoidFunction)vkGetFenceStatus; 10639 if (!strcmp(funcName, "vkQueueWaitIdle")) 10640 return (PFN_vkVoidFunction)vkQueueWaitIdle; 10641 if (!strcmp(funcName, "vkDeviceWaitIdle")) 10642 return (PFN_vkVoidFunction)vkDeviceWaitIdle; 10643 if (!strcmp(funcName, "vkGetDeviceQueue")) 10644 return (PFN_vkVoidFunction)vkGetDeviceQueue; 10645 if (!strcmp(funcName, "vkDestroyInstance")) 10646 return (PFN_vkVoidFunction)vkDestroyInstance; 10647 if (!strcmp(funcName, "vkDestroyDevice")) 10648 return (PFN_vkVoidFunction)vkDestroyDevice; 10649 if (!strcmp(funcName, "vkDestroyFence")) 10650 return (PFN_vkVoidFunction)vkDestroyFence; 10651 if (!strcmp(funcName, "vkResetFences")) 10652 return (PFN_vkVoidFunction)vkResetFences; 10653 if (!strcmp(funcName, "vkDestroySemaphore")) 10654 return (PFN_vkVoidFunction)vkDestroySemaphore; 10655 if (!strcmp(funcName, "vkDestroyEvent")) 10656 return (PFN_vkVoidFunction)vkDestroyEvent; 10657 if (!strcmp(funcName, "vkDestroyQueryPool")) 10658 return (PFN_vkVoidFunction)vkDestroyQueryPool; 10659 if (!strcmp(funcName, "vkDestroyBuffer")) 10660 return (PFN_vkVoidFunction)vkDestroyBuffer; 10661 if (!strcmp(funcName, "vkDestroyBufferView")) 10662 return (PFN_vkVoidFunction)vkDestroyBufferView; 10663 if (!strcmp(funcName, "vkDestroyImage")) 10664 return (PFN_vkVoidFunction)vkDestroyImage; 10665 if (!strcmp(funcName, "vkDestroyImageView")) 10666 return (PFN_vkVoidFunction)vkDestroyImageView; 10667 if (!strcmp(funcName, "vkDestroyShaderModule")) 10668 return (PFN_vkVoidFunction)vkDestroyShaderModule; 10669 if (!strcmp(funcName, "vkDestroyPipeline")) 10670 return (PFN_vkVoidFunction)vkDestroyPipeline; 10671 if (!strcmp(funcName, "vkDestroyPipelineLayout")) 10672 return (PFN_vkVoidFunction)vkDestroyPipelineLayout; 10673 if (!strcmp(funcName, "vkDestroySampler")) 10674 return (PFN_vkVoidFunction)vkDestroySampler; 10675 if (!strcmp(funcName, "vkDestroyDescriptorSetLayout")) 10676 return (PFN_vkVoidFunction)vkDestroyDescriptorSetLayout; 10677 if (!strcmp(funcName, "vkDestroyDescriptorPool")) 10678 return (PFN_vkVoidFunction)vkDestroyDescriptorPool; 10679 if (!strcmp(funcName, "vkDestroyFramebuffer")) 10680 return (PFN_vkVoidFunction)vkDestroyFramebuffer; 10681 if (!strcmp(funcName, "vkDestroyRenderPass")) 10682 return (PFN_vkVoidFunction)vkDestroyRenderPass; 10683 if (!strcmp(funcName, "vkCreateBuffer")) 10684 return (PFN_vkVoidFunction)vkCreateBuffer; 10685 if (!strcmp(funcName, "vkCreateBufferView")) 10686 return (PFN_vkVoidFunction)vkCreateBufferView; 10687 if (!strcmp(funcName, "vkCreateImage")) 10688 return (PFN_vkVoidFunction)vkCreateImage; 10689 if (!strcmp(funcName, "vkCreateImageView")) 10690 return (PFN_vkVoidFunction)vkCreateImageView; 10691 if (!strcmp(funcName, "vkCreateFence")) 10692 return (PFN_vkVoidFunction)vkCreateFence; 10693 if (!strcmp(funcName, "CreatePipelineCache")) 10694 return (PFN_vkVoidFunction)vkCreatePipelineCache; 10695 if (!strcmp(funcName, "DestroyPipelineCache")) 10696 return (PFN_vkVoidFunction)vkDestroyPipelineCache; 10697 if (!strcmp(funcName, "GetPipelineCacheData")) 10698 return (PFN_vkVoidFunction)vkGetPipelineCacheData; 10699 if (!strcmp(funcName, "MergePipelineCaches")) 10700 return (PFN_vkVoidFunction)vkMergePipelineCaches; 10701 if (!strcmp(funcName, "vkCreateGraphicsPipelines")) 10702 return (PFN_vkVoidFunction)vkCreateGraphicsPipelines; 10703 if (!strcmp(funcName, "vkCreateComputePipelines")) 10704 return (PFN_vkVoidFunction)vkCreateComputePipelines; 10705 if (!strcmp(funcName, "vkCreateSampler")) 10706 return (PFN_vkVoidFunction)vkCreateSampler; 10707 if (!strcmp(funcName, "vkCreateDescriptorSetLayout")) 10708 return (PFN_vkVoidFunction)vkCreateDescriptorSetLayout; 10709 if (!strcmp(funcName, "vkCreatePipelineLayout")) 10710 return (PFN_vkVoidFunction)vkCreatePipelineLayout; 10711 if (!strcmp(funcName, "vkCreateDescriptorPool")) 10712 return (PFN_vkVoidFunction)vkCreateDescriptorPool; 10713 if (!strcmp(funcName, "vkResetDescriptorPool")) 10714 return (PFN_vkVoidFunction)vkResetDescriptorPool; 10715 if (!strcmp(funcName, "vkAllocateDescriptorSets")) 10716 return (PFN_vkVoidFunction)vkAllocateDescriptorSets; 10717 if (!strcmp(funcName, "vkFreeDescriptorSets")) 10718 return (PFN_vkVoidFunction)vkFreeDescriptorSets; 10719 if (!strcmp(funcName, "vkUpdateDescriptorSets")) 10720 return (PFN_vkVoidFunction)vkUpdateDescriptorSets; 10721 if (!strcmp(funcName, "vkCreateCommandPool")) 10722 return (PFN_vkVoidFunction)vkCreateCommandPool; 10723 if (!strcmp(funcName, "vkDestroyCommandPool")) 10724 return (PFN_vkVoidFunction)vkDestroyCommandPool; 10725 if (!strcmp(funcName, "vkResetCommandPool")) 10726 return (PFN_vkVoidFunction)vkResetCommandPool; 10727 if (!strcmp(funcName, "vkCreateQueryPool")) 10728 return (PFN_vkVoidFunction)vkCreateQueryPool; 10729 if (!strcmp(funcName, "vkAllocateCommandBuffers")) 10730 return (PFN_vkVoidFunction)vkAllocateCommandBuffers; 10731 if (!strcmp(funcName, "vkFreeCommandBuffers")) 10732 return (PFN_vkVoidFunction)vkFreeCommandBuffers; 10733 if (!strcmp(funcName, "vkBeginCommandBuffer")) 10734 return (PFN_vkVoidFunction)vkBeginCommandBuffer; 10735 if (!strcmp(funcName, "vkEndCommandBuffer")) 10736 return (PFN_vkVoidFunction)vkEndCommandBuffer; 10737 if (!strcmp(funcName, "vkResetCommandBuffer")) 10738 return (PFN_vkVoidFunction)vkResetCommandBuffer; 10739 if (!strcmp(funcName, "vkCmdBindPipeline")) 10740 return (PFN_vkVoidFunction)vkCmdBindPipeline; 10741 if (!strcmp(funcName, "vkCmdSetViewport")) 10742 return (PFN_vkVoidFunction)vkCmdSetViewport; 10743 if (!strcmp(funcName, "vkCmdSetScissor")) 10744 return (PFN_vkVoidFunction)vkCmdSetScissor; 10745 if (!strcmp(funcName, "vkCmdSetLineWidth")) 10746 return (PFN_vkVoidFunction)vkCmdSetLineWidth; 10747 if (!strcmp(funcName, "vkCmdSetDepthBias")) 10748 return (PFN_vkVoidFunction)vkCmdSetDepthBias; 10749 if (!strcmp(funcName, "vkCmdSetBlendConstants")) 10750 return (PFN_vkVoidFunction)vkCmdSetBlendConstants; 10751 if (!strcmp(funcName, "vkCmdSetDepthBounds")) 10752 return (PFN_vkVoidFunction)vkCmdSetDepthBounds; 10753 if (!strcmp(funcName, "vkCmdSetStencilCompareMask")) 10754 return (PFN_vkVoidFunction)vkCmdSetStencilCompareMask; 10755 if (!strcmp(funcName, "vkCmdSetStencilWriteMask")) 10756 return (PFN_vkVoidFunction)vkCmdSetStencilWriteMask; 10757 if (!strcmp(funcName, "vkCmdSetStencilReference")) 10758 return (PFN_vkVoidFunction)vkCmdSetStencilReference; 10759 if (!strcmp(funcName, "vkCmdBindDescriptorSets")) 10760 return (PFN_vkVoidFunction)vkCmdBindDescriptorSets; 10761 if (!strcmp(funcName, "vkCmdBindVertexBuffers")) 10762 return (PFN_vkVoidFunction)vkCmdBindVertexBuffers; 10763 if (!strcmp(funcName, "vkCmdBindIndexBuffer")) 10764 return (PFN_vkVoidFunction)vkCmdBindIndexBuffer; 10765 if (!strcmp(funcName, "vkCmdDraw")) 10766 return (PFN_vkVoidFunction)vkCmdDraw; 10767 if (!strcmp(funcName, "vkCmdDrawIndexed")) 10768 return (PFN_vkVoidFunction)vkCmdDrawIndexed; 10769 if (!strcmp(funcName, "vkCmdDrawIndirect")) 10770 return (PFN_vkVoidFunction)vkCmdDrawIndirect; 10771 if (!strcmp(funcName, "vkCmdDrawIndexedIndirect")) 10772 return (PFN_vkVoidFunction)vkCmdDrawIndexedIndirect; 10773 if (!strcmp(funcName, "vkCmdDispatch")) 10774 return (PFN_vkVoidFunction)vkCmdDispatch; 10775 if (!strcmp(funcName, "vkCmdDispatchIndirect")) 10776 return (PFN_vkVoidFunction)vkCmdDispatchIndirect; 10777 if (!strcmp(funcName, "vkCmdCopyBuffer")) 10778 return (PFN_vkVoidFunction)vkCmdCopyBuffer; 10779 if (!strcmp(funcName, "vkCmdCopyImage")) 10780 return (PFN_vkVoidFunction)vkCmdCopyImage; 10781 if (!strcmp(funcName, "vkCmdBlitImage")) 10782 return (PFN_vkVoidFunction)vkCmdBlitImage; 10783 if (!strcmp(funcName, "vkCmdCopyBufferToImage")) 10784 return (PFN_vkVoidFunction)vkCmdCopyBufferToImage; 10785 if (!strcmp(funcName, "vkCmdCopyImageToBuffer")) 10786 return (PFN_vkVoidFunction)vkCmdCopyImageToBuffer; 10787 if (!strcmp(funcName, "vkCmdUpdateBuffer")) 10788 return (PFN_vkVoidFunction)vkCmdUpdateBuffer; 10789 if (!strcmp(funcName, "vkCmdFillBuffer")) 10790 return (PFN_vkVoidFunction)vkCmdFillBuffer; 10791 if (!strcmp(funcName, "vkCmdClearColorImage")) 10792 return (PFN_vkVoidFunction)vkCmdClearColorImage; 10793 if (!strcmp(funcName, "vkCmdClearDepthStencilImage")) 10794 return (PFN_vkVoidFunction)vkCmdClearDepthStencilImage; 10795 if (!strcmp(funcName, "vkCmdClearAttachments")) 10796 return (PFN_vkVoidFunction)vkCmdClearAttachments; 10797 if (!strcmp(funcName, "vkCmdResolveImage")) 10798 return (PFN_vkVoidFunction)vkCmdResolveImage; 10799 if (!strcmp(funcName, "vkCmdSetEvent")) 10800 return (PFN_vkVoidFunction)vkCmdSetEvent; 10801 if (!strcmp(funcName, "vkCmdResetEvent")) 10802 return (PFN_vkVoidFunction)vkCmdResetEvent; 10803 if (!strcmp(funcName, "vkCmdWaitEvents")) 10804 return (PFN_vkVoidFunction)vkCmdWaitEvents; 10805 if (!strcmp(funcName, "vkCmdPipelineBarrier")) 10806 return (PFN_vkVoidFunction)vkCmdPipelineBarrier; 10807 if (!strcmp(funcName, "vkCmdBeginQuery")) 10808 return (PFN_vkVoidFunction)vkCmdBeginQuery; 10809 if (!strcmp(funcName, "vkCmdEndQuery")) 10810 return (PFN_vkVoidFunction)vkCmdEndQuery; 10811 if (!strcmp(funcName, "vkCmdResetQueryPool")) 10812 return (PFN_vkVoidFunction)vkCmdResetQueryPool; 10813 if (!strcmp(funcName, "vkCmdCopyQueryPoolResults")) 10814 return (PFN_vkVoidFunction)vkCmdCopyQueryPoolResults; 10815 if (!strcmp(funcName, "vkCmdPushConstants")) 10816 return (PFN_vkVoidFunction)vkCmdPushConstants; 10817 if (!strcmp(funcName, "vkCmdWriteTimestamp")) 10818 return (PFN_vkVoidFunction)vkCmdWriteTimestamp; 10819 if (!strcmp(funcName, "vkCreateFramebuffer")) 10820 return (PFN_vkVoidFunction)vkCreateFramebuffer; 10821 if (!strcmp(funcName, "vkCreateShaderModule")) 10822 return (PFN_vkVoidFunction)vkCreateShaderModule; 10823 if (!strcmp(funcName, "vkCreateRenderPass")) 10824 return (PFN_vkVoidFunction)vkCreateRenderPass; 10825 if (!strcmp(funcName, "vkCmdBeginRenderPass")) 10826 return (PFN_vkVoidFunction)vkCmdBeginRenderPass; 10827 if (!strcmp(funcName, "vkCmdNextSubpass")) 10828 return (PFN_vkVoidFunction)vkCmdNextSubpass; 10829 if (!strcmp(funcName, "vkCmdEndRenderPass")) 10830 return (PFN_vkVoidFunction)vkCmdEndRenderPass; 10831 if (!strcmp(funcName, "vkCmdExecuteCommands")) 10832 return (PFN_vkVoidFunction)vkCmdExecuteCommands; 10833 if (!strcmp(funcName, "vkSetEvent")) 10834 return (PFN_vkVoidFunction)vkSetEvent; 10835 if (!strcmp(funcName, "vkMapMemory")) 10836 return (PFN_vkVoidFunction)vkMapMemory; 10837#if MTMERGESOURCE 10838 if (!strcmp(funcName, "vkUnmapMemory")) 10839 return (PFN_vkVoidFunction)vkUnmapMemory; 10840 if (!strcmp(funcName, "vkAllocateMemory")) 10841 return (PFN_vkVoidFunction)vkAllocateMemory; 10842 if (!strcmp(funcName, "vkFreeMemory")) 10843 return (PFN_vkVoidFunction)vkFreeMemory; 10844 if (!strcmp(funcName, "vkFlushMappedMemoryRanges")) 10845 return (PFN_vkVoidFunction)vkFlushMappedMemoryRanges; 10846 if (!strcmp(funcName, "vkInvalidateMappedMemoryRanges")) 10847 return (PFN_vkVoidFunction)vkInvalidateMappedMemoryRanges; 10848 if (!strcmp(funcName, "vkBindBufferMemory")) 10849 return (PFN_vkVoidFunction)vkBindBufferMemory; 10850 if (!strcmp(funcName, "vkGetBufferMemoryRequirements")) 10851 return (PFN_vkVoidFunction)vkGetBufferMemoryRequirements; 10852 if (!strcmp(funcName, "vkGetImageMemoryRequirements")) 10853 return (PFN_vkVoidFunction)vkGetImageMemoryRequirements; 10854#endif 10855 if (!strcmp(funcName, "vkGetQueryPoolResults")) 10856 return (PFN_vkVoidFunction)vkGetQueryPoolResults; 10857 if (!strcmp(funcName, "vkBindImageMemory")) 10858 return (PFN_vkVoidFunction)vkBindImageMemory; 10859 if (!strcmp(funcName, "vkQueueBindSparse")) 10860 return (PFN_vkVoidFunction)vkQueueBindSparse; 10861 if (!strcmp(funcName, "vkCreateSemaphore")) 10862 return (PFN_vkVoidFunction)vkCreateSemaphore; 10863 if (!strcmp(funcName, "vkCreateEvent")) 10864 return (PFN_vkVoidFunction)vkCreateEvent; 10865 10866 if (dev == NULL) 10867 return NULL; 10868 10869 layer_data *dev_data; 10870 dev_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map); 10871 10872 if (dev_data->device_extensions.wsi_enabled) { 10873 if (!strcmp(funcName, "vkCreateSwapchainKHR")) 10874 return (PFN_vkVoidFunction)vkCreateSwapchainKHR; 10875 if (!strcmp(funcName, "vkDestroySwapchainKHR")) 10876 return (PFN_vkVoidFunction)vkDestroySwapchainKHR; 10877 if (!strcmp(funcName, "vkGetSwapchainImagesKHR")) 10878 return (PFN_vkVoidFunction)vkGetSwapchainImagesKHR; 10879 if (!strcmp(funcName, "vkAcquireNextImageKHR")) 10880 return (PFN_vkVoidFunction)vkAcquireNextImageKHR; 10881 if (!strcmp(funcName, "vkQueuePresentKHR")) 10882 return (PFN_vkVoidFunction)vkQueuePresentKHR; 10883 } 10884 10885 VkLayerDispatchTable *pTable = dev_data->device_dispatch_table; 10886 { 10887 if (pTable->GetDeviceProcAddr == NULL) 10888 return NULL; 10889 return pTable->GetDeviceProcAddr(dev, funcName); 10890 } 10891} 10892 10893VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) { 10894 if (!strcmp(funcName, "vkGetInstanceProcAddr")) 10895 return (PFN_vkVoidFunction)vkGetInstanceProcAddr; 10896 if (!strcmp(funcName, "vkGetDeviceProcAddr")) 10897 return (PFN_vkVoidFunction)vkGetDeviceProcAddr; 10898 if (!strcmp(funcName, "vkCreateInstance")) 10899 return (PFN_vkVoidFunction)vkCreateInstance; 10900 if (!strcmp(funcName, "vkCreateDevice")) 10901 return (PFN_vkVoidFunction)vkCreateDevice; 10902 if (!strcmp(funcName, "vkDestroyInstance")) 10903 return (PFN_vkVoidFunction)vkDestroyInstance; 10904#if MTMERGESOURCE 10905 if (!strcmp(funcName, "vkGetPhysicalDeviceMemoryProperties")) 10906 return (PFN_vkVoidFunction)vkGetPhysicalDeviceMemoryProperties; 10907#endif 10908 if (!strcmp(funcName, "vkEnumerateInstanceLayerProperties")) 10909 return (PFN_vkVoidFunction)vkEnumerateInstanceLayerProperties; 10910 if (!strcmp(funcName, "vkEnumerateInstanceExtensionProperties")) 10911 return (PFN_vkVoidFunction)vkEnumerateInstanceExtensionProperties; 10912 if (!strcmp(funcName, "vkEnumerateDeviceLayerProperties")) 10913 return (PFN_vkVoidFunction)vkEnumerateDeviceLayerProperties; 10914 if (!strcmp(funcName, "vkEnumerateDeviceExtensionProperties")) 10915 return (PFN_vkVoidFunction)vkEnumerateDeviceExtensionProperties; 10916 10917 if (instance == NULL) 10918 return NULL; 10919 10920 PFN_vkVoidFunction fptr; 10921 10922 layer_data *my_data; 10923 my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); 10924 fptr = debug_report_get_instance_proc_addr(my_data->report_data, funcName); 10925 if (fptr) 10926 return fptr; 10927 10928 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; 10929 if (pTable->GetInstanceProcAddr == NULL) 10930 return NULL; 10931 return pTable->GetInstanceProcAddr(instance, funcName); 10932} 10933