core_validation.cpp revision 58070a671b39e2058a799c7b9c932f3f03f2e66d
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 MTMERGE 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 MTMERGE 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 MTMERGE 110// MTMERGE - stuff pulled directly from MT 111 uint64_t currentFenceId; 112 // Maps for tracking key structs related to mem_tracker state 113 unordered_map<VkCommandBuffer, MT_CB_INFO> cbMap; 114 // Merged w/ draw_state maps below 115 //unordered_map<VkCommandPool, MT_CMD_POOL_INFO> commandPoolMap; 116 //unordered_map<VkFence, MT_FENCE_INFO> fenceMap; 117 //unordered_map<VkQueue, MT_QUEUE_INFO> queueMap; 118 //unordered_map<VkSemaphore, MtSemaphoreState> semaphoreMap; 119 //unordered_map<VkImageView, MT_IMAGE_VIEW_INFO> imageViewMap; 120 //unordered_map<VkBufferView, VkBufferViewCreateInfo> bufferViewMap; 121 unordered_map<VkFramebuffer, MT_FB_INFO> fbMap; 122 unordered_map<VkRenderPass, MT_PASS_INFO> passMap; 123 unordered_map<VkDescriptorSet, MT_DESCRIPTOR_SET_INFO> descriptorSetMap; 124 // Images and Buffers are 2 objects that can have memory bound to them so they get special treatment 125 unordered_map<uint64_t, MT_OBJ_BINDING_INFO> imageBindingMap; 126 unordered_map<uint64_t, MT_OBJ_BINDING_INFO> bufferBindingMap; 127// MTMERGE - End of MT stuff 128#endif 129 devExts device_extensions; 130 vector<VkQueue> queues; // all queues under given device 131 // Global set of all cmdBuffers that are inFlight on this device 132 unordered_set<VkCommandBuffer> globalInFlightCmdBuffers; 133 // Layer specific data 134 unordered_map<VkSampler, unique_ptr<SAMPLER_NODE>> sampleMap; 135 unordered_map<VkImageView, VkImageViewCreateInfo> imageViewMap; 136 unordered_map<VkImage, IMAGE_NODE> imageMap; 137 unordered_map<VkBufferView, VkBufferViewCreateInfo> bufferViewMap; 138 unordered_map<VkBuffer, BUFFER_NODE> bufferMap; 139 unordered_map<VkPipeline, PIPELINE_NODE *> pipelineMap; 140 unordered_map<VkCommandPool, CMD_POOL_INFO> commandPoolMap; 141 unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_NODE *> descriptorPoolMap; 142 unordered_map<VkDescriptorSet, SET_NODE *> setMap; 143 unordered_map<VkDescriptorSetLayout, LAYOUT_NODE *> descriptorSetLayoutMap; 144 unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap; 145 unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> memObjMap; 146 unordered_map<VkFence, FENCE_NODE> fenceMap; 147 unordered_map<VkQueue, QUEUE_NODE> queueMap; 148 unordered_map<VkEvent, EVENT_NODE> eventMap; 149 unordered_map<QueryObject, bool> queryToStateMap; 150 unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap; 151 unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap; 152 unordered_map<void *, GLOBAL_CB_NODE *> commandBufferMap; 153 unordered_map<VkFramebuffer, FRAMEBUFFER_NODE> frameBufferMap; 154 unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap; 155 unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap; 156 unordered_map<VkRenderPass, RENDER_PASS_NODE *> renderPassMap; 157 unordered_map<VkShaderModule, shader_module *> shaderModuleMap; 158 // Current render pass 159 VkRenderPassBeginInfo renderPassBeginInfo; 160 uint32_t currentSubpass; 161 162 // Device specific data 163 PHYS_DEV_PROPERTIES_NODE physDevProperties; 164// MTMERGE - added a couple of fields to constructor initializer 165 layer_data() 166 : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), 167#if MTMERGE 168 currentFenceId(1), 169#endif 170 device_extensions(){}; 171}; 172 173static const VkLayerProperties cv_global_layers[] = {{ 174 "VK_LAYER_LUNARG_core_validation", VK_API_VERSION, 1, "LunarG Validation Layer", 175}}; 176 177template <class TCreateInfo> void ValidateLayerOrdering(const TCreateInfo &createInfo) { 178 bool foundLayer = false; 179 for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) { 180 if (!strcmp(createInfo.ppEnabledLayerNames[i], cv_global_layers[0].layerName)) { 181 foundLayer = true; 182 } 183 // This has to be logged to console as we don't have a callback at this point. 184 if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) { 185 LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.", 186 cv_global_layers[0].layerName); 187 } 188 } 189} 190 191// Code imported from shader_checker 192static void build_def_index(shader_module *); 193 194// A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words 195// without the caller needing to care too much about the physical SPIRV module layout. 196struct spirv_inst_iter { 197 std::vector<uint32_t>::const_iterator zero; 198 std::vector<uint32_t>::const_iterator it; 199 200 uint32_t len() { return *it >> 16; } 201 uint32_t opcode() { return *it & 0x0ffffu; } 202 uint32_t const &word(unsigned n) { return it[n]; } 203 uint32_t offset() { return (uint32_t)(it - zero); } 204 205 spirv_inst_iter() {} 206 207 spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {} 208 209 bool operator==(spirv_inst_iter const &other) { return it == other.it; } 210 211 bool operator!=(spirv_inst_iter const &other) { return it != other.it; } 212 213 spirv_inst_iter operator++(int) { /* x++ */ 214 spirv_inst_iter ii = *this; 215 it += len(); 216 return ii; 217 } 218 219 spirv_inst_iter operator++() { /* ++x; */ 220 it += len(); 221 return *this; 222 } 223 224 /* The iterator and the value are the same thing. */ 225 spirv_inst_iter &operator*() { return *this; } 226 spirv_inst_iter const &operator*() const { return *this; } 227}; 228 229struct shader_module { 230 /* the spirv image itself */ 231 vector<uint32_t> words; 232 /* a mapping of <id> to the first word of its def. this is useful because walking type 233 * trees, constant expressions, etc requires jumping all over the instruction stream. 234 */ 235 unordered_map<unsigned, unsigned> def_index; 236 237 shader_module(VkShaderModuleCreateInfo const *pCreateInfo) 238 : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)), 239 def_index() { 240 241 build_def_index(this); 242 } 243 244 /* expose begin() / end() to enable range-based for */ 245 spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); } /* first insn */ 246 spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); } /* just past last insn */ 247 /* given an offset into the module, produce an iterator there. */ 248 spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); } 249 250 /* gets an iterator to the definition of an id */ 251 spirv_inst_iter get_def(unsigned id) const { 252 auto it = def_index.find(id); 253 if (it == def_index.end()) { 254 return end(); 255 } 256 return at(it->second); 257 } 258}; 259 260// TODO : Do we need to guard access to layer_data_map w/ lock? 261static unordered_map<void *, layer_data *> layer_data_map; 262 263// TODO : This can be much smarter, using separate locks for separate global data 264static int globalLockInitialized = 0; 265static loader_platform_thread_mutex globalLock; 266#define MAX_TID 513 267static loader_platform_thread_id g_tidMapping[MAX_TID] = {0}; 268static uint32_t g_maxTID = 0; 269#if MTMERGE 270// MTMERGE - start of direct pull 271static VkPhysicalDeviceMemoryProperties memProps; 272 273static VkBool32 clear_cmd_buf_and_mem_references(layer_data *my_data, const VkCommandBuffer cb); 274 275#define MAX_BINDING 0xFFFFFFFF 276 277static MT_OBJ_BINDING_INFO *get_object_binding_info(layer_data *my_data, uint64_t handle, VkDebugReportObjectTypeEXT type) { 278 MT_OBJ_BINDING_INFO *retValue = NULL; 279 switch (type) { 280 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: { 281 auto it = my_data->imageBindingMap.find(handle); 282 if (it != my_data->imageBindingMap.end()) 283 return &(*it).second; 284 break; 285 } 286 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: { 287 auto it = my_data->bufferBindingMap.find(handle); 288 if (it != my_data->bufferBindingMap.end()) 289 return &(*it).second; 290 break; 291 } 292 default: 293 break; 294 } 295 return retValue; 296} 297// MTMERGE - end section 298#endif 299template layer_data *get_my_data_ptr<layer_data>(void *data_key, std::unordered_map<void *, layer_data *> &data_map); 300 301#if MTMERGE 302static void delete_queue_info_list(layer_data *my_data) { 303 // Process queue list, cleaning up each entry before deleting 304 my_data->queueMap.clear(); 305} 306 307// Add new CBInfo for this cb to map container 308static void add_cmd_buf_info(layer_data *my_data, VkCommandPool commandPool, const VkCommandBuffer cb) { 309 my_data->cbMap[cb].commandBuffer = cb; 310 my_data->commandPoolMap[commandPool].commandBuffers.push_front(cb); 311} 312 313// Delete CBInfo from container and clear mem references to CB 314static VkBool32 delete_cmd_buf_info(layer_data *my_data, VkCommandPool commandPool, const VkCommandBuffer cb) { 315 VkBool32 result = VK_TRUE; 316 result = clear_cmd_buf_and_mem_references(my_data, cb); 317 // Delete the CBInfo info 318 if (result != VK_TRUE) { 319 my_data->commandPoolMap[commandPool].commandBuffers.remove(cb); 320 my_data->cbMap.erase(cb); 321 } 322 return result; 323} 324 325// Return ptr to Info in CB map, or NULL if not found 326static MT_CB_INFO *get_cmd_buf_info(layer_data *my_data, const VkCommandBuffer cb) { 327 auto item = my_data->cbMap.find(cb); 328 if (item != my_data->cbMap.end()) { 329 return &(*item).second; 330 } else { 331 return NULL; 332 } 333} 334 335static void add_object_binding_info(layer_data *my_data, const uint64_t handle, const VkDebugReportObjectTypeEXT type, 336 const VkDeviceMemory mem) { 337 switch (type) { 338 // Buffers and images are unique as their CreateInfo is in container struct 339 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: { 340 auto pCI = &my_data->bufferBindingMap[handle]; 341 pCI->mem = mem; 342 break; 343 } 344 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: { 345 auto pCI = &my_data->imageBindingMap[handle]; 346 pCI->mem = mem; 347 break; 348 } 349 default: 350 break; 351 } 352} 353 354static void add_object_create_info(layer_data *my_data, const uint64_t handle, const VkDebugReportObjectTypeEXT type, 355 const void *pCreateInfo) { 356 // TODO : For any CreateInfo struct that has ptrs, need to deep copy them and appropriately clean up on Destroy 357 switch (type) { 358 // Buffers and images are unique as their CreateInfo is in container struct 359 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: { 360 auto pCI = &my_data->bufferBindingMap[handle]; 361 memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO)); 362 memcpy(&pCI->create_info.buffer, pCreateInfo, sizeof(VkBufferCreateInfo)); 363 break; 364 } 365 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: { 366 auto pCI = &my_data->imageBindingMap[handle]; 367 memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO)); 368 memcpy(&pCI->create_info.image, pCreateInfo, sizeof(VkImageCreateInfo)); 369 break; 370 } 371 // Swap Chain is very unique, use my_data->imageBindingMap, but copy in 372 // SwapChainCreatInfo's usage flags and set the mem value to a unique key. These is used by 373 // vkCreateImageView and internal mem_tracker routines to distinguish swap chain images 374 case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: { 375 auto pCI = &my_data->imageBindingMap[handle]; 376 memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO)); 377 pCI->mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY; 378 pCI->valid = false; 379 pCI->create_info.image.usage = 380 const_cast<VkSwapchainCreateInfoKHR *>(static_cast<const VkSwapchainCreateInfoKHR *>(pCreateInfo))->imageUsage; 381 break; 382 } 383 default: 384 break; 385 } 386} 387 388// Add a fence, creating one if necessary to our list of fences/fenceIds 389static VkBool32 add_fence_info(layer_data *my_data, VkFence fence, VkQueue queue, uint64_t *fenceId) { 390 VkBool32 skipCall = VK_FALSE; 391 *fenceId = my_data->currentFenceId++; 392 393 // If no fence, create an internal fence to track the submissions 394 if (fence != VK_NULL_HANDLE) { 395 my_data->fenceMap[fence].fenceId = *fenceId; 396 my_data->fenceMap[fence].queue = queue; 397 // Validate that fence is in UNSIGNALED state 398 VkFenceCreateInfo *pFenceCI = &(my_data->fenceMap[fence].createInfo); 399 if (pFenceCI->flags & VK_FENCE_CREATE_SIGNALED_BIT) { 400 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 401 (uint64_t)fence, __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", 402 "Fence %#" PRIxLEAST64 " submitted in SIGNALED state. Fences must be reset before being submitted", 403 (uint64_t)fence); 404 } 405 } else { 406 // TODO : Do we need to create an internal fence here for tracking purposes? 407 } 408 // Update most recently submitted fence and fenceId for Queue 409 my_data->queueMap[queue].lastSubmittedId = *fenceId; 410 return skipCall; 411} 412 413// Remove a fenceInfo from our list of fences/fenceIds 414static void delete_fence_info(layer_data *my_data, VkFence fence) { my_data->fenceMap.erase(fence); } 415 416// Record information when a fence is known to be signalled 417static void update_fence_tracking(layer_data *my_data, VkFence fence) { 418 auto fence_item = my_data->fenceMap.find(fence); 419 if (fence_item != my_data->fenceMap.end()) { 420 FENCE_NODE *pCurFenceInfo = &(*fence_item).second; 421 VkQueue queue = pCurFenceInfo->queue; 422 auto queue_item = my_data->queueMap.find(queue); 423 if (queue_item != my_data->queueMap.end()) { 424 QUEUE_NODE *pQueueInfo = &(*queue_item).second; 425 if (pQueueInfo->lastRetiredId < pCurFenceInfo->fenceId) { 426 pQueueInfo->lastRetiredId = pCurFenceInfo->fenceId; 427 } 428 } 429 } 430 431 // Update fence state in fenceCreateInfo structure 432 auto pFCI = &(my_data->fenceMap[fence].createInfo); 433 pFCI->flags = static_cast<VkFenceCreateFlags>(pFCI->flags | VK_FENCE_CREATE_SIGNALED_BIT); 434} 435 436// Helper routine that updates the fence list for a specific queue to all-retired 437static void retire_queue_fences(layer_data *my_data, VkQueue queue) { 438 QUEUE_NODE *pQueueInfo = &my_data->queueMap[queue]; 439 // Set queue's lastRetired to lastSubmitted indicating all fences completed 440 pQueueInfo->lastRetiredId = pQueueInfo->lastSubmittedId; 441} 442 443// Helper routine that updates all queues to all-retired 444static void retire_device_fences(layer_data *my_data, VkDevice device) { 445 // Process each queue for device 446 // TODO: Add multiple device support 447 for (auto ii = my_data->queueMap.begin(); ii != my_data->queueMap.end(); ++ii) { 448 // Set queue's lastRetired to lastSubmitted indicating all fences completed 449 QUEUE_NODE *pQueueInfo = &(*ii).second; 450 pQueueInfo->lastRetiredId = pQueueInfo->lastSubmittedId; 451 } 452} 453 454// Helper function to validate correct usage bits set for buffers or images 455// Verify that (actual & desired) flags != 0 or, 456// if strict is true, verify that (actual & desired) flags == desired 457// In case of error, report it via dbg callbacks 458static VkBool32 validate_usage_flags(layer_data *my_data, void *disp_obj, VkFlags actual, VkFlags desired, VkBool32 strict, 459 uint64_t obj_handle, VkDebugReportObjectTypeEXT obj_type, char const *ty_str, 460 char const *func_name, char const *usage_str) { 461 VkBool32 correct_usage = VK_FALSE; 462 VkBool32 skipCall = VK_FALSE; 463 if (strict) 464 correct_usage = ((actual & desired) == desired); 465 else 466 correct_usage = ((actual & desired) != 0); 467 if (!correct_usage) { 468 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_type, obj_handle, __LINE__, 469 MEMTRACK_INVALID_USAGE_FLAG, "MEM", "Invalid usage flag for %s %#" PRIxLEAST64 470 " used by %s. In this case, %s should have %s set during creation.", 471 ty_str, obj_handle, func_name, ty_str, usage_str); 472 } 473 return skipCall; 474} 475 476// Helper function to validate usage flags for images 477// Pulls image info and then sends actual vs. desired usage off to helper above where 478// an error will be flagged if usage is not correct 479static VkBool32 validate_image_usage_flags(layer_data *my_data, void *disp_obj, VkImage image, VkFlags desired, VkBool32 strict, 480 char const *func_name, char const *usage_string) { 481 VkBool32 skipCall = VK_FALSE; 482 MT_OBJ_BINDING_INFO *pBindInfo = get_object_binding_info(my_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); 483 if (pBindInfo) { 484 skipCall = validate_usage_flags(my_data, disp_obj, pBindInfo->create_info.image.usage, desired, strict, (uint64_t)image, 485 VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "image", func_name, usage_string); 486 } 487 return skipCall; 488} 489 490// Helper function to validate usage flags for buffers 491// Pulls buffer info and then sends actual vs. desired usage off to helper above where 492// an error will be flagged if usage is not correct 493static VkBool32 validate_buffer_usage_flags(layer_data *my_data, void *disp_obj, VkBuffer buffer, VkFlags desired, VkBool32 strict, 494 char const *func_name, char const *usage_string) { 495 VkBool32 skipCall = VK_FALSE; 496 MT_OBJ_BINDING_INFO *pBindInfo = get_object_binding_info(my_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT); 497 if (pBindInfo) { 498 skipCall = validate_usage_flags(my_data, disp_obj, pBindInfo->create_info.buffer.usage, desired, strict, (uint64_t)buffer, 499 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "buffer", func_name, usage_string); 500 } 501 return skipCall; 502} 503 504// Return ptr to info in map container containing mem, or NULL if not found 505// Calls to this function should be wrapped in mutex 506static DEVICE_MEM_INFO *get_mem_obj_info(layer_data *dev_data, const VkDeviceMemory mem) { 507 auto item = dev_data->memObjMap.find(mem); 508 if (item != dev_data->memObjMap.end()) { 509 return &(*item).second; 510 } else { 511 return NULL; 512 } 513} 514 515static void add_mem_obj_info(layer_data *my_data, void *object, const VkDeviceMemory mem, 516 const VkMemoryAllocateInfo *pAllocateInfo) { 517 assert(object != NULL); 518 519 memcpy(&my_data->memObjMap[mem].allocInfo, pAllocateInfo, sizeof(VkMemoryAllocateInfo)); 520 // TODO: Update for real hardware, actually process allocation info structures 521 my_data->memObjMap[mem].allocInfo.pNext = NULL; 522 my_data->memObjMap[mem].object = object; 523 my_data->memObjMap[mem].refCount = 0; 524 my_data->memObjMap[mem].mem = mem; 525 my_data->memObjMap[mem].image = VK_NULL_HANDLE; 526 my_data->memObjMap[mem].memRange.offset = 0; 527 my_data->memObjMap[mem].memRange.size = 0; 528 my_data->memObjMap[mem].pData = 0; 529 my_data->memObjMap[mem].pDriverData = 0; 530 my_data->memObjMap[mem].valid = false; 531} 532 533static VkBool32 validate_memory_is_valid(layer_data *dev_data, VkDeviceMemory mem, const char *functionName, 534 VkImage image = VK_NULL_HANDLE) { 535 if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) { 536 MT_OBJ_BINDING_INFO *pBindInfo = 537 get_object_binding_info(dev_data, reinterpret_cast<const uint64_t &>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); 538 if (pBindInfo && !pBindInfo->valid) { 539 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 540 (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM", 541 "%s: Cannot read invalid swapchain image %" PRIx64 ", please fill the memory before using.", 542 functionName, (uint64_t)(image)); 543 } 544 } else { 545 DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem); 546 if (pMemObj && !pMemObj->valid) { 547 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 548 (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM", 549 "%s: Cannot read invalid memory %" PRIx64 ", please fill the memory before using.", functionName, 550 (uint64_t)(mem)); 551 } 552 } 553 return false; 554} 555 556static void set_memory_valid(layer_data *dev_data, VkDeviceMemory mem, bool valid, VkImage image = VK_NULL_HANDLE) { 557 if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) { 558 MT_OBJ_BINDING_INFO *pBindInfo = 559 get_object_binding_info(dev_data, reinterpret_cast<const uint64_t &>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); 560 if (pBindInfo) { 561 pBindInfo->valid = valid; 562 } 563 } else { 564 DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem); 565 if (pMemObj) { 566 pMemObj->valid = valid; 567 } 568 } 569} 570 571// Find CB Info and add mem reference to list container 572// Find Mem Obj Info and add CB reference to list container 573static VkBool32 update_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb, const VkDeviceMemory mem, 574 const char *apiName) { 575 VkBool32 skipCall = VK_FALSE; 576 577 // Skip validation if this image was created through WSI 578 if (mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) { 579 580 // First update CB binding in MemObj mini CB list 581 DEVICE_MEM_INFO *pMemInfo = get_mem_obj_info(dev_data, mem); 582 if (pMemInfo) { 583 // Search for cmd buffer object in memory object's binding list 584 VkBool32 found = VK_FALSE; 585 if (pMemInfo->pCommandBufferBindings.size() > 0) { 586 for (list<VkCommandBuffer>::iterator it = pMemInfo->pCommandBufferBindings.begin(); 587 it != pMemInfo->pCommandBufferBindings.end(); ++it) { 588 if ((*it) == cb) { 589 found = VK_TRUE; 590 break; 591 } 592 } 593 } 594 // If not present, add to list 595 if (found == VK_FALSE) { 596 pMemInfo->pCommandBufferBindings.push_front(cb); 597 pMemInfo->refCount++; 598 } 599 // Now update CBInfo's Mem reference list 600 MT_CB_INFO *pCBInfo = get_cmd_buf_info(dev_data, cb); 601 // TODO: keep track of all destroyed CBs so we know if this is a stale or simply invalid object 602 if (pCBInfo) { 603 // Search for memory object in cmd buffer's reference list 604 VkBool32 found = VK_FALSE; 605 if (pCBInfo->pMemObjList.size() > 0) { 606 for (auto it = pCBInfo->pMemObjList.begin(); it != pCBInfo->pMemObjList.end(); ++it) { 607 if ((*it) == mem) { 608 found = VK_TRUE; 609 break; 610 } 611 } 612 } 613 // If not present, add to list 614 if (found == VK_FALSE) { 615 pCBInfo->pMemObjList.push_front(mem); 616 } 617 } 618 } 619 } 620 return skipCall; 621} 622 623// Free bindings related to CB 624static VkBool32 clear_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb) { 625 VkBool32 skipCall = VK_FALSE; 626 MT_CB_INFO *pCBInfo = get_cmd_buf_info(dev_data, cb); 627 628 if (pCBInfo) { 629 if (pCBInfo->pMemObjList.size() > 0) { 630 list<VkDeviceMemory> mem_obj_list = pCBInfo->pMemObjList; 631 for (list<VkDeviceMemory>::iterator it = mem_obj_list.begin(); it != mem_obj_list.end(); ++it) { 632 DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, *it); 633 if (pInfo) { 634 pInfo->pCommandBufferBindings.remove(cb); 635 pInfo->refCount--; 636 } 637 } 638 pCBInfo->pMemObjList.clear(); 639 } 640 pCBInfo->activeDescriptorSets.clear(); 641 pCBInfo->validate_functions.clear(); 642 } 643 return skipCall; 644} 645 646// Delete the entire CB list 647static VkBool32 delete_cmd_buf_info_list(layer_data *my_data) { 648 VkBool32 skipCall = VK_FALSE; 649 for (unordered_map<VkCommandBuffer, MT_CB_INFO>::iterator ii = my_data->cbMap.begin(); ii != my_data->cbMap.end(); ++ii) { 650 skipCall |= clear_cmd_buf_and_mem_references(my_data, (*ii).first); 651 } 652 my_data->cbMap.clear(); 653 return skipCall; 654} 655 656// For given MemObjInfo, report Obj & CB bindings 657static VkBool32 reportMemReferencesAndCleanUp(layer_data *dev_data, DEVICE_MEM_INFO *pMemObjInfo) { 658 VkBool32 skipCall = VK_FALSE; 659 size_t cmdBufRefCount = pMemObjInfo->pCommandBufferBindings.size(); 660 size_t objRefCount = pMemObjInfo->pObjBindings.size(); 661 662 if ((pMemObjInfo->pCommandBufferBindings.size()) != 0) { 663 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 664 (uint64_t)pMemObjInfo->mem, __LINE__, MEMTRACK_FREED_MEM_REF, "MEM", 665 "Attempting to free memory object %#" PRIxLEAST64 " which still contains " PRINTF_SIZE_T_SPECIFIER 666 " references", 667 (uint64_t)pMemObjInfo->mem, (cmdBufRefCount + objRefCount)); 668 } 669 670 if (cmdBufRefCount > 0 && pMemObjInfo->pCommandBufferBindings.size() > 0) { 671 for (list<VkCommandBuffer>::const_iterator it = pMemObjInfo->pCommandBufferBindings.begin(); 672 it != pMemObjInfo->pCommandBufferBindings.end(); ++it) { 673 // TODO : CommandBuffer should be source Obj here 674 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 675 (uint64_t)(*it), __LINE__, MEMTRACK_FREED_MEM_REF, "MEM", 676 "Command Buffer %p still has a reference to mem obj %#" PRIxLEAST64, (*it), (uint64_t)pMemObjInfo->mem); 677 } 678 // Clear the list of hanging references 679 pMemObjInfo->pCommandBufferBindings.clear(); 680 } 681 682 if (objRefCount > 0 && pMemObjInfo->pObjBindings.size() > 0) { 683 for (auto it = pMemObjInfo->pObjBindings.begin(); it != pMemObjInfo->pObjBindings.end(); ++it) { 684 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, it->type, it->handle, __LINE__, 685 MEMTRACK_FREED_MEM_REF, "MEM", "VK Object %#" PRIxLEAST64 " still has a reference to mem obj %#" PRIxLEAST64, 686 it->handle, (uint64_t)pMemObjInfo->mem); 687 } 688 // Clear the list of hanging references 689 pMemObjInfo->pObjBindings.clear(); 690 } 691 return skipCall; 692} 693 694static VkBool32 deleteMemObjInfo(layer_data *my_data, void *object, VkDeviceMemory mem) { 695 VkBool32 skipCall = VK_FALSE; 696 auto item = my_data->memObjMap.find(mem); 697 if (item != my_data->memObjMap.end()) { 698 my_data->memObjMap.erase(item); 699 } else { 700 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 701 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM", 702 "Request to delete memory object %#" PRIxLEAST64 " not present in memory Object Map", (uint64_t)mem); 703 } 704 return skipCall; 705} 706 707// Check if fence for given CB is completed 708static bool checkCBCompleted(layer_data *my_data, const VkCommandBuffer cb, bool *complete) { 709 MT_CB_INFO *pCBInfo = get_cmd_buf_info(my_data, cb); 710 VkBool32 skipCall = false; 711 *complete = true; 712 713 if (pCBInfo) { 714 if (pCBInfo->lastSubmittedQueue != NULL) { 715 VkQueue queue = pCBInfo->lastSubmittedQueue; 716 QUEUE_NODE *pQueueInfo = &my_data->queueMap[queue]; 717 if (pCBInfo->fenceId > pQueueInfo->lastRetiredId) { 718 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 719 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)cb, __LINE__, MEMTRACK_NONE, "MEM", 720 "fence %#" PRIxLEAST64 " for CB %p has not been checked for completion", 721 (uint64_t)pCBInfo->lastSubmittedFence, cb); 722 *complete = false; 723 } 724 } 725 } 726 return skipCall; 727} 728 729static VkBool32 freeMemObjInfo(layer_data *dev_data, void *object, VkDeviceMemory mem, VkBool32 internal) { 730 VkBool32 skipCall = VK_FALSE; 731 // Parse global list to find info w/ mem 732 DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem); 733 if (pInfo) { 734 if (pInfo->allocInfo.allocationSize == 0 && !internal) { 735 // TODO: Verify against Valid Use section 736 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 737 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM", 738 "Attempting to free memory associated with a Persistent Image, %#" PRIxLEAST64 ", " 739 "this should not be explicitly freed\n", 740 (uint64_t)mem); 741 } else { 742 // Clear any CB bindings for completed CBs 743 // TODO : Is there a better place to do this? 744 745 bool commandBufferComplete = false; 746 assert(pInfo->object != VK_NULL_HANDLE); 747 list<VkCommandBuffer>::iterator it = pInfo->pCommandBufferBindings.begin(); 748 list<VkCommandBuffer>::iterator temp; 749 while (pInfo->pCommandBufferBindings.size() > 0 && it != pInfo->pCommandBufferBindings.end()) { 750 skipCall |= checkCBCompleted(dev_data, *it, &commandBufferComplete); 751 if (commandBufferComplete) { 752 temp = it; 753 ++temp; 754 skipCall |= clear_cmd_buf_and_mem_references(dev_data, *it); 755 it = temp; 756 } else { 757 ++it; 758 } 759 } 760 761 // Now verify that no references to this mem obj remain and remove bindings 762 if (0 != pInfo->refCount) { 763 skipCall |= reportMemReferencesAndCleanUp(dev_data, pInfo); 764 } 765 // Delete mem obj info 766 skipCall |= deleteMemObjInfo(dev_data, object, mem); 767 } 768 } 769 return skipCall; 770} 771 772static const char *object_type_to_string(VkDebugReportObjectTypeEXT type) { 773 switch (type) { 774 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: 775 return "image"; 776 break; 777 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: 778 return "buffer"; 779 break; 780 case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: 781 return "swapchain"; 782 break; 783 default: 784 return "unknown"; 785 } 786} 787 788// Remove object binding performs 3 tasks: 789// 1. Remove ObjectInfo from MemObjInfo list container of obj bindings & free it 790// 2. Decrement refCount for MemObjInfo 791// 3. Clear mem binding for image/buffer by setting its handle to 0 792// TODO : This only applied to Buffer, Image, and Swapchain objects now, how should it be updated/customized? 793static VkBool32 clear_object_binding(layer_data *dev_data, void *dispObj, uint64_t handle, VkDebugReportObjectTypeEXT type) { 794 // TODO : Need to customize images/buffers/swapchains to track mem binding and clear it here appropriately 795 VkBool32 skipCall = VK_FALSE; 796 MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(dev_data, handle, type); 797 if (pObjBindInfo) { 798 DEVICE_MEM_INFO *pMemObjInfo = get_mem_obj_info(dev_data, pObjBindInfo->mem); 799 // TODO : Make sure this is a reasonable way to reset mem binding 800 pObjBindInfo->mem = VK_NULL_HANDLE; 801 if (pMemObjInfo) { 802 // This obj is bound to a memory object. Remove the reference to this object in that memory object's list, decrement the 803 // memObj's refcount 804 // and set the objects memory binding pointer to NULL. 805 VkBool32 clearSucceeded = VK_FALSE; 806 for (auto it = pMemObjInfo->pObjBindings.begin(); it != pMemObjInfo->pObjBindings.end(); ++it) { 807 if ((it->handle == handle) && (it->type == type)) { 808 pMemObjInfo->refCount--; 809 pMemObjInfo->pObjBindings.erase(it); 810 clearSucceeded = VK_TRUE; 811 break; 812 } 813 } 814 if (VK_FALSE == clearSucceeded) { 815 skipCall |= 816 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT, 817 "MEM", "While trying to clear mem binding for %s obj %#" PRIxLEAST64 818 ", unable to find that object referenced by mem obj %#" PRIxLEAST64, 819 object_type_to_string(type), handle, (uint64_t)pMemObjInfo->mem); 820 } 821 } 822 } 823 return skipCall; 824} 825 826// For NULL mem case, output warning 827// Make sure given object is in global object map 828// IF a previous binding existed, output validation error 829// Otherwise, add reference from objectInfo to memoryInfo 830// Add reference off of objInfo 831// device is required for error logging, need a dispatchable 832// object for that. 833static VkBool32 set_mem_binding(layer_data *dev_data, void *dispatch_object, VkDeviceMemory mem, uint64_t handle, 834 VkDebugReportObjectTypeEXT type, const char *apiName) { 835 VkBool32 skipCall = VK_FALSE; 836 // Handle NULL case separately, just clear previous binding & decrement reference 837 if (mem == VK_NULL_HANDLE) { 838 // TODO: Verify against Valid Use section of spec. 839 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_MEM_OBJ, 840 "MEM", "In %s, attempting to Bind Obj(%#" PRIxLEAST64 ") to NULL", apiName, handle); 841 } else { 842 MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(dev_data, handle, type); 843 if (!pObjBindInfo) { 844 skipCall |= 845 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS, 846 "MEM", "In %s, attempting to update Binding of %s Obj(%#" PRIxLEAST64 ") that's not in global list()", 847 object_type_to_string(type), apiName, handle); 848 } else { 849 // non-null case so should have real mem obj 850 DEVICE_MEM_INFO *pMemInfo = get_mem_obj_info(dev_data, mem); 851 if (pMemInfo) { 852 // TODO : Need to track mem binding for obj and report conflict here 853 DEVICE_MEM_INFO *pPrevBinding = get_mem_obj_info(dev_data, pObjBindInfo->mem); 854 if (pPrevBinding != NULL) { 855 skipCall |= 856 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 857 (uint64_t)mem, __LINE__, MEMTRACK_REBIND_OBJECT, "MEM", 858 "In %s, attempting to bind memory (%#" PRIxLEAST64 ") to object (%#" PRIxLEAST64 859 ") which has already been bound to mem object %#" PRIxLEAST64, 860 apiName, (uint64_t)mem, handle, (uint64_t)pPrevBinding->mem); 861 } else { 862 MT_OBJ_HANDLE_TYPE oht; 863 oht.handle = handle; 864 oht.type = type; 865 pMemInfo->pObjBindings.push_front(oht); 866 pMemInfo->refCount++; 867 // For image objects, make sure default memory state is correctly set 868 // TODO : What's the best/correct way to handle this? 869 if (VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT == type) { 870 VkImageCreateInfo ici = pObjBindInfo->create_info.image; 871 if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { 872 // TODO:: More memory state transition stuff. 873 } 874 } 875 pObjBindInfo->mem = mem; 876 } 877 } 878 } 879 } 880 return skipCall; 881} 882 883// For NULL mem case, clear any previous binding Else... 884// Make sure given object is in its object map 885// IF a previous binding existed, update binding 886// Add reference from objectInfo to memoryInfo 887// Add reference off of object's binding info 888// Return VK_TRUE if addition is successful, VK_FALSE otherwise 889static VkBool32 set_sparse_mem_binding(layer_data *dev_data, void *dispObject, VkDeviceMemory mem, uint64_t handle, 890 VkDebugReportObjectTypeEXT type, const char *apiName) { 891 VkBool32 skipCall = VK_FALSE; 892 // Handle NULL case separately, just clear previous binding & decrement reference 893 if (mem == VK_NULL_HANDLE) { 894 skipCall = clear_object_binding(dev_data, dispObject, handle, type); 895 } else { 896 MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(dev_data, handle, type); 897 if (!pObjBindInfo) { 898 skipCall |= log_msg( 899 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS, "MEM", 900 "In %s, attempting to update Binding of Obj(%#" PRIxLEAST64 ") that's not in global list()", apiName, handle); 901 } 902 // non-null case so should have real mem obj 903 DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem); 904 if (pInfo) { 905 // Search for object in memory object's binding list 906 VkBool32 found = VK_FALSE; 907 if (pInfo->pObjBindings.size() > 0) { 908 for (auto it = pInfo->pObjBindings.begin(); it != pInfo->pObjBindings.end(); ++it) { 909 if (((*it).handle == handle) && ((*it).type == type)) { 910 found = VK_TRUE; 911 break; 912 } 913 } 914 } 915 // If not present, add to list 916 if (found == VK_FALSE) { 917 MT_OBJ_HANDLE_TYPE oht; 918 oht.handle = handle; 919 oht.type = type; 920 pInfo->pObjBindings.push_front(oht); 921 pInfo->refCount++; 922 } 923 // Need to set mem binding for this object 924 pObjBindInfo->mem = mem; 925 } 926 } 927 return skipCall; 928} 929 930template <typename T> 931void print_object_map_members(layer_data *my_data, void *dispObj, T const &objectName, VkDebugReportObjectTypeEXT objectType, 932 const char *objectStr) { 933 for (auto const &element : objectName) { 934 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objectType, 0, __LINE__, MEMTRACK_NONE, "MEM", 935 " %s Object list contains %s Object %#" PRIxLEAST64 " ", objectStr, objectStr, element.first); 936 } 937} 938 939// For given Object, get 'mem' obj that it's bound to or NULL if no binding 940static VkBool32 get_mem_binding_from_object(layer_data *my_data, void *dispObj, const uint64_t handle, 941 const VkDebugReportObjectTypeEXT type, VkDeviceMemory *mem) { 942 VkBool32 skipCall = VK_FALSE; 943 *mem = VK_NULL_HANDLE; 944 MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(my_data, handle, type); 945 if (pObjBindInfo) { 946 if (pObjBindInfo->mem) { 947 *mem = pObjBindInfo->mem; 948 } else { 949 skipCall = 950 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS, 951 "MEM", "Trying to get mem binding for object %#" PRIxLEAST64 " but object has no mem binding", handle); 952 } 953 } else { 954 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT, 955 "MEM", "Trying to get mem binding for object %#" PRIxLEAST64 " but no such object in %s list", handle, 956 object_type_to_string(type)); 957 } 958 return skipCall; 959} 960 961// Print details of MemObjInfo list 962static void print_mem_list(layer_data *dev_data, void *dispObj) { 963 DEVICE_MEM_INFO *pInfo = NULL; 964 965 // Early out if info is not requested 966 if (!(dev_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) { 967 return; 968 } 969 970 // Just printing each msg individually for now, may want to package these into single large print 971 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, 972 MEMTRACK_NONE, "MEM", "Details of Memory Object list (of size " PRINTF_SIZE_T_SPECIFIER " elements)", 973 dev_data->memObjMap.size()); 974 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, 975 MEMTRACK_NONE, "MEM", "============================="); 976 977 if (dev_data->memObjMap.size() <= 0) 978 return; 979 980 for (auto ii = dev_data->memObjMap.begin(); ii != dev_data->memObjMap.end(); ++ii) { 981 pInfo = &(*ii).second; 982 983 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 984 __LINE__, MEMTRACK_NONE, "MEM", " ===MemObjInfo at %p===", (void *)pInfo); 985 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 986 __LINE__, MEMTRACK_NONE, "MEM", " Mem object: %#" PRIxLEAST64, (uint64_t)(pInfo->mem)); 987 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 988 __LINE__, MEMTRACK_NONE, "MEM", " Ref Count: %u", pInfo->refCount); 989 if (0 != pInfo->allocInfo.allocationSize) { 990 string pAllocInfoMsg = vk_print_vkmemoryallocateinfo(&pInfo->allocInfo, "MEM(INFO): "); 991 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 992 __LINE__, MEMTRACK_NONE, "MEM", " Mem Alloc info:\n%s", pAllocInfoMsg.c_str()); 993 } else { 994 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 995 __LINE__, MEMTRACK_NONE, "MEM", " Mem Alloc info is NULL (alloc done by vkCreateSwapchainKHR())"); 996 } 997 998 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 999 __LINE__, MEMTRACK_NONE, "MEM", " VK OBJECT Binding list of size " PRINTF_SIZE_T_SPECIFIER " elements:", 1000 pInfo->pObjBindings.size()); 1001 if (pInfo->pObjBindings.size() > 0) { 1002 for (list<MT_OBJ_HANDLE_TYPE>::iterator it = pInfo->pObjBindings.begin(); it != pInfo->pObjBindings.end(); ++it) { 1003 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 1004 0, __LINE__, MEMTRACK_NONE, "MEM", " VK OBJECT %" PRIu64, it->handle); 1005 } 1006 } 1007 1008 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 1009 __LINE__, MEMTRACK_NONE, "MEM", 1010 " VK Command Buffer (CB) binding list of size " PRINTF_SIZE_T_SPECIFIER " elements", 1011 pInfo->pCommandBufferBindings.size()); 1012 if (pInfo->pCommandBufferBindings.size() > 0) { 1013 for (list<VkCommandBuffer>::iterator it = pInfo->pCommandBufferBindings.begin(); 1014 it != pInfo->pCommandBufferBindings.end(); ++it) { 1015 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 1016 0, __LINE__, MEMTRACK_NONE, "MEM", " VK CB %p", (*it)); 1017 } 1018 } 1019 } 1020} 1021 1022static void printCBList(layer_data *my_data, void *dispObj) { 1023 MT_CB_INFO *pCBInfo = NULL; 1024 1025 // Early out if info is not requested 1026 if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) { 1027 return; 1028 } 1029 1030 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, 1031 MEMTRACK_NONE, "MEM", "Details of CB list (of size " PRINTF_SIZE_T_SPECIFIER " elements)", my_data->cbMap.size()); 1032 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, 1033 MEMTRACK_NONE, "MEM", "=================="); 1034 1035 if (my_data->cbMap.size() <= 0) 1036 return; 1037 1038 for (auto ii = my_data->cbMap.begin(); ii != my_data->cbMap.end(); ++ii) { 1039 pCBInfo = &(*ii).second; 1040 1041 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 1042 __LINE__, MEMTRACK_NONE, "MEM", " CB Info (%p) has CB %p, fenceId %" PRIx64 ", and fence %#" PRIxLEAST64, 1043 (void *)pCBInfo, (void *)pCBInfo->commandBuffer, pCBInfo->fenceId, (uint64_t)pCBInfo->lastSubmittedFence); 1044 1045 if (pCBInfo->pMemObjList.size() <= 0) 1046 continue; 1047 for (list<VkDeviceMemory>::iterator it = pCBInfo->pMemObjList.begin(); it != pCBInfo->pMemObjList.end(); ++it) { 1048 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, 1049 __LINE__, MEMTRACK_NONE, "MEM", " Mem obj %" PRIu64, (uint64_t)(*it)); 1050 } 1051 } 1052} 1053 1054#endif 1055 1056// Map actual TID to an index value and return that index 1057// This keeps TIDs in range from 0-MAX_TID and simplifies compares between runs 1058static uint32_t getTIDIndex() { 1059 loader_platform_thread_id tid = loader_platform_get_thread_id(); 1060 for (uint32_t i = 0; i < g_maxTID; i++) { 1061 if (tid == g_tidMapping[i]) 1062 return i; 1063 } 1064 // Don't yet have mapping, set it and return newly set index 1065 uint32_t retVal = (uint32_t)g_maxTID; 1066 g_tidMapping[g_maxTID++] = tid; 1067 assert(g_maxTID < MAX_TID); 1068 return retVal; 1069} 1070 1071// Return a string representation of CMD_TYPE enum 1072static string cmdTypeToString(CMD_TYPE cmd) { 1073 switch (cmd) { 1074 case CMD_BINDPIPELINE: 1075 return "CMD_BINDPIPELINE"; 1076 case CMD_BINDPIPELINEDELTA: 1077 return "CMD_BINDPIPELINEDELTA"; 1078 case CMD_SETVIEWPORTSTATE: 1079 return "CMD_SETVIEWPORTSTATE"; 1080 case CMD_SETLINEWIDTHSTATE: 1081 return "CMD_SETLINEWIDTHSTATE"; 1082 case CMD_SETDEPTHBIASSTATE: 1083 return "CMD_SETDEPTHBIASSTATE"; 1084 case CMD_SETBLENDSTATE: 1085 return "CMD_SETBLENDSTATE"; 1086 case CMD_SETDEPTHBOUNDSSTATE: 1087 return "CMD_SETDEPTHBOUNDSSTATE"; 1088 case CMD_SETSTENCILREADMASKSTATE: 1089 return "CMD_SETSTENCILREADMASKSTATE"; 1090 case CMD_SETSTENCILWRITEMASKSTATE: 1091 return "CMD_SETSTENCILWRITEMASKSTATE"; 1092 case CMD_SETSTENCILREFERENCESTATE: 1093 return "CMD_SETSTENCILREFERENCESTATE"; 1094 case CMD_BINDDESCRIPTORSETS: 1095 return "CMD_BINDDESCRIPTORSETS"; 1096 case CMD_BINDINDEXBUFFER: 1097 return "CMD_BINDINDEXBUFFER"; 1098 case CMD_BINDVERTEXBUFFER: 1099 return "CMD_BINDVERTEXBUFFER"; 1100 case CMD_DRAW: 1101 return "CMD_DRAW"; 1102 case CMD_DRAWINDEXED: 1103 return "CMD_DRAWINDEXED"; 1104 case CMD_DRAWINDIRECT: 1105 return "CMD_DRAWINDIRECT"; 1106 case CMD_DRAWINDEXEDINDIRECT: 1107 return "CMD_DRAWINDEXEDINDIRECT"; 1108 case CMD_DISPATCH: 1109 return "CMD_DISPATCH"; 1110 case CMD_DISPATCHINDIRECT: 1111 return "CMD_DISPATCHINDIRECT"; 1112 case CMD_COPYBUFFER: 1113 return "CMD_COPYBUFFER"; 1114 case CMD_COPYIMAGE: 1115 return "CMD_COPYIMAGE"; 1116 case CMD_BLITIMAGE: 1117 return "CMD_BLITIMAGE"; 1118 case CMD_COPYBUFFERTOIMAGE: 1119 return "CMD_COPYBUFFERTOIMAGE"; 1120 case CMD_COPYIMAGETOBUFFER: 1121 return "CMD_COPYIMAGETOBUFFER"; 1122 case CMD_CLONEIMAGEDATA: 1123 return "CMD_CLONEIMAGEDATA"; 1124 case CMD_UPDATEBUFFER: 1125 return "CMD_UPDATEBUFFER"; 1126 case CMD_FILLBUFFER: 1127 return "CMD_FILLBUFFER"; 1128 case CMD_CLEARCOLORIMAGE: 1129 return "CMD_CLEARCOLORIMAGE"; 1130 case CMD_CLEARATTACHMENTS: 1131 return "CMD_CLEARCOLORATTACHMENT"; 1132 case CMD_CLEARDEPTHSTENCILIMAGE: 1133 return "CMD_CLEARDEPTHSTENCILIMAGE"; 1134 case CMD_RESOLVEIMAGE: 1135 return "CMD_RESOLVEIMAGE"; 1136 case CMD_SETEVENT: 1137 return "CMD_SETEVENT"; 1138 case CMD_RESETEVENT: 1139 return "CMD_RESETEVENT"; 1140 case CMD_WAITEVENTS: 1141 return "CMD_WAITEVENTS"; 1142 case CMD_PIPELINEBARRIER: 1143 return "CMD_PIPELINEBARRIER"; 1144 case CMD_BEGINQUERY: 1145 return "CMD_BEGINQUERY"; 1146 case CMD_ENDQUERY: 1147 return "CMD_ENDQUERY"; 1148 case CMD_RESETQUERYPOOL: 1149 return "CMD_RESETQUERYPOOL"; 1150 case CMD_COPYQUERYPOOLRESULTS: 1151 return "CMD_COPYQUERYPOOLRESULTS"; 1152 case CMD_WRITETIMESTAMP: 1153 return "CMD_WRITETIMESTAMP"; 1154 case CMD_INITATOMICCOUNTERS: 1155 return "CMD_INITATOMICCOUNTERS"; 1156 case CMD_LOADATOMICCOUNTERS: 1157 return "CMD_LOADATOMICCOUNTERS"; 1158 case CMD_SAVEATOMICCOUNTERS: 1159 return "CMD_SAVEATOMICCOUNTERS"; 1160 case CMD_BEGINRENDERPASS: 1161 return "CMD_BEGINRENDERPASS"; 1162 case CMD_ENDRENDERPASS: 1163 return "CMD_ENDRENDERPASS"; 1164 default: 1165 return "UNKNOWN"; 1166 } 1167} 1168 1169// SPIRV utility functions 1170static void build_def_index(shader_module *module) { 1171 for (auto insn : *module) { 1172 switch (insn.opcode()) { 1173 /* Types */ 1174 case spv::OpTypeVoid: 1175 case spv::OpTypeBool: 1176 case spv::OpTypeInt: 1177 case spv::OpTypeFloat: 1178 case spv::OpTypeVector: 1179 case spv::OpTypeMatrix: 1180 case spv::OpTypeImage: 1181 case spv::OpTypeSampler: 1182 case spv::OpTypeSampledImage: 1183 case spv::OpTypeArray: 1184 case spv::OpTypeRuntimeArray: 1185 case spv::OpTypeStruct: 1186 case spv::OpTypeOpaque: 1187 case spv::OpTypePointer: 1188 case spv::OpTypeFunction: 1189 case spv::OpTypeEvent: 1190 case spv::OpTypeDeviceEvent: 1191 case spv::OpTypeReserveId: 1192 case spv::OpTypeQueue: 1193 case spv::OpTypePipe: 1194 module->def_index[insn.word(1)] = insn.offset(); 1195 break; 1196 1197 /* Fixed constants */ 1198 case spv::OpConstantTrue: 1199 case spv::OpConstantFalse: 1200 case spv::OpConstant: 1201 case spv::OpConstantComposite: 1202 case spv::OpConstantSampler: 1203 case spv::OpConstantNull: 1204 module->def_index[insn.word(2)] = insn.offset(); 1205 break; 1206 1207 /* Specialization constants */ 1208 case spv::OpSpecConstantTrue: 1209 case spv::OpSpecConstantFalse: 1210 case spv::OpSpecConstant: 1211 case spv::OpSpecConstantComposite: 1212 case spv::OpSpecConstantOp: 1213 module->def_index[insn.word(2)] = insn.offset(); 1214 break; 1215 1216 /* Variables */ 1217 case spv::OpVariable: 1218 module->def_index[insn.word(2)] = insn.offset(); 1219 break; 1220 1221 /* Functions */ 1222 case spv::OpFunction: 1223 module->def_index[insn.word(2)] = insn.offset(); 1224 break; 1225 1226 default: 1227 /* We don't care about any other defs for now. */ 1228 break; 1229 } 1230 } 1231} 1232 1233static spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) { 1234 for (auto insn : *src) { 1235 if (insn.opcode() == spv::OpEntryPoint) { 1236 auto entrypointName = (char const *)&insn.word(3); 1237 auto entrypointStageBits = 1u << insn.word(1); 1238 1239 if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) { 1240 return insn; 1241 } 1242 } 1243 } 1244 1245 return src->end(); 1246} 1247 1248bool shader_is_spirv(VkShaderModuleCreateInfo const *pCreateInfo) { 1249 uint32_t *words = (uint32_t *)pCreateInfo->pCode; 1250 size_t sizeInWords = pCreateInfo->codeSize / sizeof(uint32_t); 1251 1252 /* Just validate that the header makes sense. */ 1253 return sizeInWords >= 5 && words[0] == spv::MagicNumber && words[1] == spv::Version; 1254} 1255 1256static char const *storage_class_name(unsigned sc) { 1257 switch (sc) { 1258 case spv::StorageClassInput: 1259 return "input"; 1260 case spv::StorageClassOutput: 1261 return "output"; 1262 case spv::StorageClassUniformConstant: 1263 return "const uniform"; 1264 case spv::StorageClassUniform: 1265 return "uniform"; 1266 case spv::StorageClassWorkgroup: 1267 return "workgroup local"; 1268 case spv::StorageClassCrossWorkgroup: 1269 return "workgroup global"; 1270 case spv::StorageClassPrivate: 1271 return "private global"; 1272 case spv::StorageClassFunction: 1273 return "function"; 1274 case spv::StorageClassGeneric: 1275 return "generic"; 1276 case spv::StorageClassAtomicCounter: 1277 return "atomic counter"; 1278 case spv::StorageClassImage: 1279 return "image"; 1280 case spv::StorageClassPushConstant: 1281 return "push constant"; 1282 default: 1283 return "unknown"; 1284 } 1285} 1286 1287/* get the value of an integral constant */ 1288unsigned get_constant_value(shader_module const *src, unsigned id) { 1289 auto value = src->get_def(id); 1290 assert(value != src->end()); 1291 1292 if (value.opcode() != spv::OpConstant) { 1293 /* TODO: Either ensure that the specialization transform is already performed on a module we're 1294 considering here, OR -- specialize on the fly now. 1295 */ 1296 return 1; 1297 } 1298 1299 return value.word(3); 1300} 1301 1302/* returns ptr to null terminator */ 1303static char *describe_type(char *dst, shader_module const *src, unsigned type) { 1304 auto insn = src->get_def(type); 1305 assert(insn != src->end()); 1306 1307 switch (insn.opcode()) { 1308 case spv::OpTypeBool: 1309 return dst + sprintf(dst, "bool"); 1310 case spv::OpTypeInt: 1311 return dst + sprintf(dst, "%cint%d", insn.word(3) ? 's' : 'u', insn.word(2)); 1312 case spv::OpTypeFloat: 1313 return dst + sprintf(dst, "float%d", insn.word(2)); 1314 case spv::OpTypeVector: 1315 dst += sprintf(dst, "vec%d of ", insn.word(3)); 1316 return describe_type(dst, src, insn.word(2)); 1317 case spv::OpTypeMatrix: 1318 dst += sprintf(dst, "mat%d of ", insn.word(3)); 1319 return describe_type(dst, src, insn.word(2)); 1320 case spv::OpTypeArray: 1321 dst += sprintf(dst, "arr[%d] of ", get_constant_value(src, insn.word(3))); 1322 return describe_type(dst, src, insn.word(2)); 1323 case spv::OpTypePointer: 1324 dst += sprintf(dst, "ptr to %s ", storage_class_name(insn.word(2))); 1325 return describe_type(dst, src, insn.word(3)); 1326 case spv::OpTypeStruct: { 1327 dst += sprintf(dst, "struct of ("); 1328 for (unsigned i = 2; i < insn.len(); i++) { 1329 dst = describe_type(dst, src, insn.word(i)); 1330 dst += sprintf(dst, i == insn.len() - 1 ? ")" : ", "); 1331 } 1332 return dst; 1333 } 1334 case spv::OpTypeSampler: 1335 return dst + sprintf(dst, "sampler"); 1336 case spv::OpTypeSampledImage: 1337 dst += sprintf(dst, "sampler+"); 1338 return describe_type(dst, src, insn.word(2)); 1339 case spv::OpTypeImage: 1340 dst += sprintf(dst, "image(dim=%u, sampled=%u)", insn.word(3), insn.word(7)); 1341 return dst; 1342 default: 1343 return dst + sprintf(dst, "oddtype"); 1344 } 1345} 1346 1347static bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool b_arrayed) { 1348 /* walk two type trees together, and complain about differences */ 1349 auto a_insn = a->get_def(a_type); 1350 auto b_insn = b->get_def(b_type); 1351 assert(a_insn != a->end()); 1352 assert(b_insn != b->end()); 1353 1354 if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) { 1355 /* we probably just found the extra level of arrayness in b_type: compare the type inside it to a_type */ 1356 return types_match(a, b, a_type, b_insn.word(2), false); 1357 } 1358 1359 if (a_insn.opcode() != b_insn.opcode()) { 1360 return false; 1361 } 1362 1363 switch (a_insn.opcode()) { 1364 /* if b_arrayed and we hit a leaf type, then we can't match -- there's nowhere for the extra OpTypeArray to be! */ 1365 case spv::OpTypeBool: 1366 return true && !b_arrayed; 1367 case spv::OpTypeInt: 1368 /* match on width, signedness */ 1369 return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3) && !b_arrayed; 1370 case spv::OpTypeFloat: 1371 /* match on width */ 1372 return a_insn.word(2) == b_insn.word(2) && !b_arrayed; 1373 case spv::OpTypeVector: 1374 case spv::OpTypeMatrix: 1375 /* match on element type, count. these all have the same layout. we don't get here if 1376 * b_arrayed -- that is handled above. */ 1377 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); 1378 case spv::OpTypeArray: 1379 /* match on element type, count. these all have the same layout. we don't get here if 1380 * b_arrayed. This differs from vector & matrix types in that the array size is the id of a constant instruction, 1381 * not a literal within OpTypeArray */ 1382 return !b_arrayed && types_match(a, b, a_insn.word(2), b_insn.word(2), b_arrayed) && 1383 get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3)); 1384 case spv::OpTypeStruct: 1385 /* match on all element types */ 1386 { 1387 if (b_arrayed) { 1388 /* for the purposes of matching different levels of arrayness, structs are leaves. */ 1389 return false; 1390 } 1391 1392 if (a_insn.len() != b_insn.len()) { 1393 return false; /* structs cannot match if member counts differ */ 1394 } 1395 1396 for (unsigned i = 2; i < a_insn.len(); i++) { 1397 if (!types_match(a, b, a_insn.word(i), b_insn.word(i), b_arrayed)) { 1398 return false; 1399 } 1400 } 1401 1402 return true; 1403 } 1404 case spv::OpTypePointer: 1405 /* match on pointee type. storage class is expected to differ */ 1406 return types_match(a, b, a_insn.word(3), b_insn.word(3), b_arrayed); 1407 1408 default: 1409 /* remaining types are CLisms, or may not appear in the interfaces we 1410 * are interested in. Just claim no match. 1411 */ 1412 return false; 1413 } 1414} 1415 1416static int value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def) { 1417 auto it = map.find(id); 1418 if (it == map.end()) 1419 return def; 1420 else 1421 return it->second; 1422} 1423 1424static unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) { 1425 auto insn = src->get_def(type); 1426 assert(insn != src->end()); 1427 1428 switch (insn.opcode()) { 1429 case spv::OpTypePointer: 1430 /* see through the ptr -- this is only ever at the toplevel for graphics shaders; 1431 * we're never actually passing pointers around. */ 1432 return get_locations_consumed_by_type(src, insn.word(3), strip_array_level); 1433 case spv::OpTypeArray: 1434 if (strip_array_level) { 1435 return get_locations_consumed_by_type(src, insn.word(2), false); 1436 } else { 1437 return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false); 1438 } 1439 case spv::OpTypeMatrix: 1440 /* num locations is the dimension * element size */ 1441 return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false); 1442 default: 1443 /* everything else is just 1. */ 1444 return 1; 1445 1446 /* TODO: extend to handle 64bit scalar types, whose vectors may need 1447 * multiple locations. */ 1448 } 1449} 1450 1451typedef std::pair<unsigned, unsigned> location_t; 1452typedef std::pair<unsigned, unsigned> descriptor_slot_t; 1453 1454struct interface_var { 1455 uint32_t id; 1456 uint32_t type_id; 1457 uint32_t offset; 1458 /* TODO: collect the name, too? Isn't required to be present. */ 1459}; 1460 1461static spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) { 1462 while (true) { 1463 1464 if (def.opcode() == spv::OpTypePointer) { 1465 def = src->get_def(def.word(3)); 1466 } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) { 1467 def = src->get_def(def.word(2)); 1468 is_array_of_verts = false; 1469 } else if (def.opcode() == spv::OpTypeStruct) { 1470 return def; 1471 } else { 1472 return src->end(); 1473 } 1474 } 1475} 1476 1477static void collect_interface_block_members(layer_data *my_data, VkDevice dev, shader_module const *src, 1478 std::map<location_t, interface_var> &out, 1479 std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts, 1480 uint32_t id, uint32_t type_id) { 1481 /* Walk down the type_id presented, trying to determine whether it's actually an interface block. */ 1482 auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts); 1483 if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) { 1484 /* this isn't an interface block. */ 1485 return; 1486 } 1487 1488 std::unordered_map<unsigned, unsigned> member_components; 1489 1490 /* Walk all the OpMemberDecorate for type's result id -- first pass, collect components. */ 1491 for (auto insn : *src) { 1492 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) { 1493 unsigned member_index = insn.word(2); 1494 1495 if (insn.word(3) == spv::DecorationComponent) { 1496 unsigned component = insn.word(4); 1497 member_components[member_index] = component; 1498 } 1499 } 1500 } 1501 1502 /* Second pass -- produce the output, from Location decorations */ 1503 for (auto insn : *src) { 1504 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) { 1505 unsigned member_index = insn.word(2); 1506 unsigned member_type_id = type.word(2 + member_index); 1507 1508 if (insn.word(3) == spv::DecorationLocation) { 1509 unsigned location = insn.word(4); 1510 unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false); 1511 auto component_it = member_components.find(member_index); 1512 unsigned component = component_it == member_components.end() ? 0 : component_it->second; 1513 1514 for (unsigned int offset = 0; offset < num_locations; offset++) { 1515 interface_var v; 1516 v.id = id; 1517 /* TODO: member index in interface_var too? */ 1518 v.type_id = member_type_id; 1519 v.offset = offset; 1520 out[std::make_pair(location + offset, component)] = v; 1521 } 1522 } 1523 } 1524 } 1525} 1526 1527static void collect_interface_by_location(layer_data *my_data, VkDevice dev, shader_module const *src, spirv_inst_iter entrypoint, 1528 spv::StorageClass sinterface, std::map<location_t, interface_var> &out, 1529 bool is_array_of_verts) { 1530 std::unordered_map<unsigned, unsigned> var_locations; 1531 std::unordered_map<unsigned, unsigned> var_builtins; 1532 std::unordered_map<unsigned, unsigned> var_components; 1533 std::unordered_map<unsigned, unsigned> blocks; 1534 1535 for (auto insn : *src) { 1536 1537 /* We consider two interface models: SSO rendezvous-by-location, and 1538 * builtins. Complain about anything that fits neither model. 1539 */ 1540 if (insn.opcode() == spv::OpDecorate) { 1541 if (insn.word(2) == spv::DecorationLocation) { 1542 var_locations[insn.word(1)] = insn.word(3); 1543 } 1544 1545 if (insn.word(2) == spv::DecorationBuiltIn) { 1546 var_builtins[insn.word(1)] = insn.word(3); 1547 } 1548 1549 if (insn.word(2) == spv::DecorationComponent) { 1550 var_components[insn.word(1)] = insn.word(3); 1551 } 1552 1553 if (insn.word(2) == spv::DecorationBlock) { 1554 blocks[insn.word(1)] = 1; 1555 } 1556 } 1557 } 1558 1559 /* TODO: handle grouped decorations */ 1560 /* TODO: handle index=1 dual source outputs from FS -- two vars will 1561 * have the same location, and we DONT want to clobber. */ 1562 1563 /* find the end of the entrypoint's name string. additional zero bytes follow the actual null 1564 terminator, to fill out the rest of the word - so we only need to look at the last byte in 1565 the word to determine which word contains the terminator. */ 1566 auto word = 3; 1567 while (entrypoint.word(word) & 0xff000000u) { 1568 ++word; 1569 } 1570 ++word; 1571 1572 for (; word < entrypoint.len(); word++) { 1573 auto insn = src->get_def(entrypoint.word(word)); 1574 assert(insn != src->end()); 1575 assert(insn.opcode() == spv::OpVariable); 1576 1577 if (insn.word(3) == sinterface) { 1578 unsigned id = insn.word(2); 1579 unsigned type = insn.word(1); 1580 1581 int location = value_or_default(var_locations, id, -1); 1582 int builtin = value_or_default(var_builtins, id, -1); 1583 unsigned component = value_or_default(var_components, id, 0); /* unspecified is OK, is 0 */ 1584 1585 /* All variables and interface block members in the Input or Output storage classes 1586 * must be decorated with either a builtin or an explicit location. 1587 * 1588 * TODO: integrate the interface block support here. For now, don't complain -- 1589 * a valid SPIRV module will only hit this path for the interface block case, as the 1590 * individual members of the type are decorated, rather than variable declarations. 1591 */ 1592 1593 if (location != -1) { 1594 /* A user-defined interface variable, with a location. Where a variable 1595 * occupied multiple locations, emit one result for each. */ 1596 unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts); 1597 for (unsigned int offset = 0; offset < num_locations; offset++) { 1598 interface_var v; 1599 v.id = id; 1600 v.type_id = type; 1601 v.offset = offset; 1602 out[std::make_pair(location + offset, component)] = v; 1603 } 1604 } else if (builtin == -1) { 1605 /* An interface block instance */ 1606 collect_interface_block_members(my_data, dev, src, out, blocks, is_array_of_verts, id, type); 1607 } 1608 } 1609 } 1610} 1611 1612static void collect_interface_by_descriptor_slot(layer_data *my_data, VkDevice dev, shader_module const *src, 1613 std::unordered_set<uint32_t> const &accessible_ids, 1614 std::map<descriptor_slot_t, interface_var> &out) { 1615 1616 std::unordered_map<unsigned, unsigned> var_sets; 1617 std::unordered_map<unsigned, unsigned> var_bindings; 1618 1619 for (auto insn : *src) { 1620 /* All variables in the Uniform or UniformConstant storage classes are required to be decorated with both 1621 * DecorationDescriptorSet and DecorationBinding. 1622 */ 1623 if (insn.opcode() == spv::OpDecorate) { 1624 if (insn.word(2) == spv::DecorationDescriptorSet) { 1625 var_sets[insn.word(1)] = insn.word(3); 1626 } 1627 1628 if (insn.word(2) == spv::DecorationBinding) { 1629 var_bindings[insn.word(1)] = insn.word(3); 1630 } 1631 } 1632 } 1633 1634 for (auto id : accessible_ids) { 1635 auto insn = src->get_def(id); 1636 assert(insn != src->end()); 1637 1638 if (insn.opcode() == spv::OpVariable && 1639 (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) { 1640 unsigned set = value_or_default(var_sets, insn.word(2), 0); 1641 unsigned binding = value_or_default(var_bindings, insn.word(2), 0); 1642 1643 auto existing_it = out.find(std::make_pair(set, binding)); 1644 if (existing_it != out.end()) { 1645 /* conflict within spv image */ 1646 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1647 __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC", 1648 "var %d (type %d) in %s interface in descriptor slot (%u,%u) conflicts with existing definition", 1649 insn.word(2), insn.word(1), storage_class_name(insn.word(3)), existing_it->first.first, 1650 existing_it->first.second); 1651 } 1652 1653 interface_var v; 1654 v.id = insn.word(2); 1655 v.type_id = insn.word(1); 1656 out[std::make_pair(set, binding)] = v; 1657 } 1658 } 1659} 1660 1661static bool validate_interface_between_stages(layer_data *my_data, VkDevice dev, shader_module const *producer, 1662 spirv_inst_iter producer_entrypoint, char const *producer_name, 1663 shader_module const *consumer, spirv_inst_iter consumer_entrypoint, 1664 char const *consumer_name, bool consumer_arrayed_input) { 1665 std::map<location_t, interface_var> outputs; 1666 std::map<location_t, interface_var> inputs; 1667 1668 bool pass = true; 1669 1670 collect_interface_by_location(my_data, dev, producer, producer_entrypoint, spv::StorageClassOutput, outputs, false); 1671 collect_interface_by_location(my_data, dev, consumer, consumer_entrypoint, spv::StorageClassInput, inputs, 1672 consumer_arrayed_input); 1673 1674 auto a_it = outputs.begin(); 1675 auto b_it = inputs.begin(); 1676 1677 /* maps sorted by key (location); walk them together to find mismatches */ 1678 while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) { 1679 bool a_at_end = outputs.size() == 0 || a_it == outputs.end(); 1680 bool b_at_end = inputs.size() == 0 || b_it == inputs.end(); 1681 auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first; 1682 auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first; 1683 1684 if (b_at_end || ((!a_at_end) && (a_first < b_first))) { 1685 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 1686 /*dev*/ 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", 1687 "%s writes to output location %u.%u which is not consumed by %s", producer_name, a_first.first, 1688 a_first.second, consumer_name)) { 1689 pass = false; 1690 } 1691 a_it++; 1692 } else if (a_at_end || a_first > b_first) { 1693 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1694 __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", 1695 "%s consumes input location %u.%u which is not written by %s", consumer_name, b_first.first, b_first.second, 1696 producer_name)) { 1697 pass = false; 1698 } 1699 b_it++; 1700 } else { 1701 if (types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id, consumer_arrayed_input)) { 1702 /* OK! */ 1703 } else { 1704 char producer_type[1024]; 1705 char consumer_type[1024]; 1706 describe_type(producer_type, producer, a_it->second.type_id); 1707 describe_type(consumer_type, consumer, b_it->second.type_id); 1708 1709 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1710 __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'", 1711 a_first.first, a_first.second, producer_type, consumer_type)) { 1712 pass = false; 1713 } 1714 } 1715 a_it++; 1716 b_it++; 1717 } 1718 } 1719 1720 return pass; 1721} 1722 1723enum FORMAT_TYPE { 1724 FORMAT_TYPE_UNDEFINED, 1725 FORMAT_TYPE_FLOAT, /* UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader */ 1726 FORMAT_TYPE_SINT, 1727 FORMAT_TYPE_UINT, 1728}; 1729 1730static unsigned get_format_type(VkFormat fmt) { 1731 switch (fmt) { 1732 case VK_FORMAT_UNDEFINED: 1733 return FORMAT_TYPE_UNDEFINED; 1734 case VK_FORMAT_R8_SINT: 1735 case VK_FORMAT_R8G8_SINT: 1736 case VK_FORMAT_R8G8B8_SINT: 1737 case VK_FORMAT_R8G8B8A8_SINT: 1738 case VK_FORMAT_R16_SINT: 1739 case VK_FORMAT_R16G16_SINT: 1740 case VK_FORMAT_R16G16B16_SINT: 1741 case VK_FORMAT_R16G16B16A16_SINT: 1742 case VK_FORMAT_R32_SINT: 1743 case VK_FORMAT_R32G32_SINT: 1744 case VK_FORMAT_R32G32B32_SINT: 1745 case VK_FORMAT_R32G32B32A32_SINT: 1746 case VK_FORMAT_B8G8R8_SINT: 1747 case VK_FORMAT_B8G8R8A8_SINT: 1748 case VK_FORMAT_A2B10G10R10_SINT_PACK32: 1749 case VK_FORMAT_A2R10G10B10_SINT_PACK32: 1750 return FORMAT_TYPE_SINT; 1751 case VK_FORMAT_R8_UINT: 1752 case VK_FORMAT_R8G8_UINT: 1753 case VK_FORMAT_R8G8B8_UINT: 1754 case VK_FORMAT_R8G8B8A8_UINT: 1755 case VK_FORMAT_R16_UINT: 1756 case VK_FORMAT_R16G16_UINT: 1757 case VK_FORMAT_R16G16B16_UINT: 1758 case VK_FORMAT_R16G16B16A16_UINT: 1759 case VK_FORMAT_R32_UINT: 1760 case VK_FORMAT_R32G32_UINT: 1761 case VK_FORMAT_R32G32B32_UINT: 1762 case VK_FORMAT_R32G32B32A32_UINT: 1763 case VK_FORMAT_B8G8R8_UINT: 1764 case VK_FORMAT_B8G8R8A8_UINT: 1765 case VK_FORMAT_A2B10G10R10_UINT_PACK32: 1766 case VK_FORMAT_A2R10G10B10_UINT_PACK32: 1767 return FORMAT_TYPE_UINT; 1768 default: 1769 return FORMAT_TYPE_FLOAT; 1770 } 1771} 1772 1773/* characterizes a SPIR-V type appearing in an interface to a FF stage, 1774 * for comparison to a VkFormat's characterization above. */ 1775static unsigned get_fundamental_type(shader_module const *src, unsigned type) { 1776 auto insn = src->get_def(type); 1777 assert(insn != src->end()); 1778 1779 switch (insn.opcode()) { 1780 case spv::OpTypeInt: 1781 return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT; 1782 case spv::OpTypeFloat: 1783 return FORMAT_TYPE_FLOAT; 1784 case spv::OpTypeVector: 1785 return get_fundamental_type(src, insn.word(2)); 1786 case spv::OpTypeMatrix: 1787 return get_fundamental_type(src, insn.word(2)); 1788 case spv::OpTypeArray: 1789 return get_fundamental_type(src, insn.word(2)); 1790 case spv::OpTypePointer: 1791 return get_fundamental_type(src, insn.word(3)); 1792 default: 1793 return FORMAT_TYPE_UNDEFINED; 1794 } 1795} 1796 1797static uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) { 1798 uint32_t bit_pos = u_ffs(stage); 1799 return bit_pos - 1; 1800} 1801 1802static bool validate_vi_consistency(layer_data *my_data, VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi) { 1803 /* walk the binding descriptions, which describe the step rate and stride of each vertex buffer. 1804 * each binding should be specified only once. 1805 */ 1806 std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings; 1807 bool pass = true; 1808 1809 for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) { 1810 auto desc = &vi->pVertexBindingDescriptions[i]; 1811 auto &binding = bindings[desc->binding]; 1812 if (binding) { 1813 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1814 __LINE__, SHADER_CHECKER_INCONSISTENT_VI, "SC", 1815 "Duplicate vertex input binding descriptions for binding %d", desc->binding)) { 1816 pass = false; 1817 } 1818 } else { 1819 binding = desc; 1820 } 1821 } 1822 1823 return pass; 1824} 1825 1826static bool validate_vi_against_vs_inputs(layer_data *my_data, VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi, 1827 shader_module const *vs, spirv_inst_iter entrypoint) { 1828 std::map<location_t, interface_var> inputs; 1829 bool pass = true; 1830 1831 collect_interface_by_location(my_data, dev, vs, entrypoint, spv::StorageClassInput, inputs, false); 1832 1833 /* Build index by location */ 1834 std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs; 1835 if (vi) { 1836 for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) 1837 attribs[vi->pVertexAttributeDescriptions[i].location] = &vi->pVertexAttributeDescriptions[i]; 1838 } 1839 1840 auto it_a = attribs.begin(); 1841 auto it_b = inputs.begin(); 1842 1843 while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) { 1844 bool a_at_end = attribs.size() == 0 || it_a == attribs.end(); 1845 bool b_at_end = inputs.size() == 0 || it_b == inputs.end(); 1846 auto a_first = a_at_end ? 0 : it_a->first; 1847 auto b_first = b_at_end ? 0 : it_b->first.first; 1848 if (!a_at_end && (b_at_end || a_first < b_first)) { 1849 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 1850 /*dev*/ 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", 1851 "Vertex attribute at location %d not consumed by VS", a_first)) { 1852 pass = false; 1853 } 1854 it_a++; 1855 } else if (!b_at_end && (a_at_end || b_first < a_first)) { 1856 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1857 __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "VS consumes input at location %d but not provided", 1858 b_first)) { 1859 pass = false; 1860 } 1861 it_b++; 1862 } else { 1863 unsigned attrib_type = get_format_type(it_a->second->format); 1864 unsigned input_type = get_fundamental_type(vs, it_b->second.type_id); 1865 1866 /* type checking */ 1867 if (attrib_type != FORMAT_TYPE_UNDEFINED && input_type != FORMAT_TYPE_UNDEFINED && attrib_type != input_type) { 1868 char vs_type[1024]; 1869 describe_type(vs_type, vs, it_b->second.type_id); 1870 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1871 __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", 1872 "Attribute type of `%s` at location %d does not match VS input type of `%s`", 1873 string_VkFormat(it_a->second->format), a_first, vs_type)) { 1874 pass = false; 1875 } 1876 } 1877 1878 /* OK! */ 1879 it_a++; 1880 it_b++; 1881 } 1882 } 1883 1884 return pass; 1885} 1886 1887static bool validate_fs_outputs_against_render_pass(layer_data *my_data, VkDevice dev, shader_module const *fs, 1888 spirv_inst_iter entrypoint, RENDER_PASS_NODE const *rp, uint32_t subpass) { 1889 const std::vector<VkFormat> &color_formats = rp->subpassColorFormats[subpass]; 1890 std::map<location_t, interface_var> outputs; 1891 bool pass = true; 1892 1893 /* TODO: dual source blend index (spv::DecIndex, zero if not provided) */ 1894 1895 collect_interface_by_location(my_data, dev, fs, entrypoint, spv::StorageClassOutput, outputs, false); 1896 1897 auto it = outputs.begin(); 1898 uint32_t attachment = 0; 1899 1900 /* Walk attachment list and outputs together -- this is a little overpowered since attachments 1901 * are currently dense, but the parallel with matching between shader stages is nice. 1902 */ 1903 1904 while ((outputs.size() > 0 && it != outputs.end()) || attachment < color_formats.size()) { 1905 if (attachment == color_formats.size() || (it != outputs.end() && it->first.first < attachment)) { 1906 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1907 __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", 1908 "FS writes to output location %d with no matching attachment", it->first.first)) { 1909 pass = false; 1910 } 1911 it++; 1912 } else if (it == outputs.end() || it->first.first > attachment) { 1913 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1914 __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by FS", attachment)) { 1915 pass = false; 1916 } 1917 attachment++; 1918 } else { 1919 unsigned output_type = get_fundamental_type(fs, it->second.type_id); 1920 unsigned att_type = get_format_type(color_formats[attachment]); 1921 1922 /* type checking */ 1923 if (att_type != FORMAT_TYPE_UNDEFINED && output_type != FORMAT_TYPE_UNDEFINED && att_type != output_type) { 1924 char fs_type[1024]; 1925 describe_type(fs_type, fs, it->second.type_id); 1926 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, 1927 __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", 1928 "Attachment %d of type `%s` does not match FS output type of `%s`", attachment, 1929 string_VkFormat(color_formats[attachment]), fs_type)) { 1930 pass = false; 1931 } 1932 } 1933 1934 /* OK! */ 1935 it++; 1936 attachment++; 1937 } 1938 } 1939 1940 return pass; 1941} 1942 1943/* For some analyses, we need to know about all ids referenced by the static call tree of a particular 1944 * entrypoint. This is important for identifying the set of shader resources actually used by an entrypoint, 1945 * for example. 1946 * Note: we only explore parts of the image which might actually contain ids we care about for the above analyses. 1947 * - NOT the shader input/output interfaces. 1948 * 1949 * TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth 1950 * converting parts of this to be generated from the machine-readable spec instead. 1951 */ 1952static void mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint, std::unordered_set<uint32_t> &ids) { 1953 std::unordered_set<uint32_t> worklist; 1954 worklist.insert(entrypoint.word(2)); 1955 1956 while (!worklist.empty()) { 1957 auto id_iter = worklist.begin(); 1958 auto id = *id_iter; 1959 worklist.erase(id_iter); 1960 1961 auto insn = src->get_def(id); 1962 if (insn == src->end()) { 1963 /* id is something we didnt collect in build_def_index. that's OK -- we'll stumble 1964 * across all kinds of things here that we may not care about. */ 1965 continue; 1966 } 1967 1968 /* try to add to the output set */ 1969 if (!ids.insert(id).second) { 1970 continue; /* if we already saw this id, we don't want to walk it again. */ 1971 } 1972 1973 switch (insn.opcode()) { 1974 case spv::OpFunction: 1975 /* scan whole body of the function, enlisting anything interesting */ 1976 while (++insn, insn.opcode() != spv::OpFunctionEnd) { 1977 switch (insn.opcode()) { 1978 case spv::OpLoad: 1979 case spv::OpAtomicLoad: 1980 case spv::OpAtomicExchange: 1981 case spv::OpAtomicCompareExchange: 1982 case spv::OpAtomicCompareExchangeWeak: 1983 case spv::OpAtomicIIncrement: 1984 case spv::OpAtomicIDecrement: 1985 case spv::OpAtomicIAdd: 1986 case spv::OpAtomicISub: 1987 case spv::OpAtomicSMin: 1988 case spv::OpAtomicUMin: 1989 case spv::OpAtomicSMax: 1990 case spv::OpAtomicUMax: 1991 case spv::OpAtomicAnd: 1992 case spv::OpAtomicOr: 1993 case spv::OpAtomicXor: 1994 worklist.insert(insn.word(3)); /* ptr */ 1995 break; 1996 case spv::OpStore: 1997 case spv::OpAtomicStore: 1998 worklist.insert(insn.word(1)); /* ptr */ 1999 break; 2000 case spv::OpAccessChain: 2001 case spv::OpInBoundsAccessChain: 2002 worklist.insert(insn.word(3)); /* base ptr */ 2003 break; 2004 case spv::OpSampledImage: 2005 case spv::OpImageSampleImplicitLod: 2006 case spv::OpImageSampleExplicitLod: 2007 case spv::OpImageSampleDrefImplicitLod: 2008 case spv::OpImageSampleDrefExplicitLod: 2009 case spv::OpImageSampleProjImplicitLod: 2010 case spv::OpImageSampleProjExplicitLod: 2011 case spv::OpImageSampleProjDrefImplicitLod: 2012 case spv::OpImageSampleProjDrefExplicitLod: 2013 case spv::OpImageFetch: 2014 case spv::OpImageGather: 2015 case spv::OpImageDrefGather: 2016 case spv::OpImageRead: 2017 case spv::OpImage: 2018 case spv::OpImageQueryFormat: 2019 case spv::OpImageQueryOrder: 2020 case spv::OpImageQuerySizeLod: 2021 case spv::OpImageQuerySize: 2022 case spv::OpImageQueryLod: 2023 case spv::OpImageQueryLevels: 2024 case spv::OpImageQuerySamples: 2025 case spv::OpImageSparseSampleImplicitLod: 2026 case spv::OpImageSparseSampleExplicitLod: 2027 case spv::OpImageSparseSampleDrefImplicitLod: 2028 case spv::OpImageSparseSampleDrefExplicitLod: 2029 case spv::OpImageSparseSampleProjImplicitLod: 2030 case spv::OpImageSparseSampleProjExplicitLod: 2031 case spv::OpImageSparseSampleProjDrefImplicitLod: 2032 case spv::OpImageSparseSampleProjDrefExplicitLod: 2033 case spv::OpImageSparseFetch: 2034 case spv::OpImageSparseGather: 2035 case spv::OpImageSparseDrefGather: 2036 case spv::OpImageTexelPointer: 2037 worklist.insert(insn.word(3)); /* image or sampled image */ 2038 break; 2039 case spv::OpImageWrite: 2040 worklist.insert(insn.word(1)); /* image -- different operand order to above */ 2041 break; 2042 case spv::OpFunctionCall: 2043 for (auto i = 3; i < insn.len(); i++) { 2044 worklist.insert(insn.word(i)); /* fn itself, and all args */ 2045 } 2046 break; 2047 2048 case spv::OpExtInst: 2049 for (auto i = 5; i < insn.len(); i++) { 2050 worklist.insert(insn.word(i)); /* operands to ext inst */ 2051 } 2052 break; 2053 } 2054 } 2055 break; 2056 } 2057 } 2058} 2059 2060struct shader_stage_attributes { 2061 char const *const name; 2062 bool arrayed_input; 2063}; 2064 2065static shader_stage_attributes shader_stage_attribs[] = { 2066 {"vertex shader", false}, 2067 {"tessellation control shader", true}, 2068 {"tessellation evaluation shader", false}, 2069 {"geometry shader", true}, 2070 {"fragment shader", false}, 2071}; 2072 2073static bool validate_push_constant_block_against_pipeline(layer_data *my_data, VkDevice dev, 2074 std::vector<VkPushConstantRange> const *pushConstantRanges, 2075 shader_module const *src, spirv_inst_iter type, 2076 VkShaderStageFlagBits stage) { 2077 bool pass = true; 2078 2079 /* strip off ptrs etc */ 2080 type = get_struct_type(src, type, false); 2081 assert(type != src->end()); 2082 2083 /* validate directly off the offsets. this isn't quite correct for arrays 2084 * and matrices, but is a good first step. TODO: arrays, matrices, weird 2085 * sizes */ 2086 for (auto insn : *src) { 2087 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) { 2088 2089 if (insn.word(3) == spv::DecorationOffset) { 2090 unsigned offset = insn.word(4); 2091 auto size = 4; /* bytes; TODO: calculate this based on the type */ 2092 2093 bool found_range = false; 2094 for (auto const &range : *pushConstantRanges) { 2095 if (range.offset <= offset && range.offset + range.size >= offset + size) { 2096 found_range = true; 2097 2098 if ((range.stageFlags & stage) == 0) { 2099 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2100 /* dev */ 0, __LINE__, SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC", 2101 "Push constant range covering variable starting at " 2102 "offset %u not accessible from stage %s", 2103 offset, string_VkShaderStageFlagBits(stage))) { 2104 pass = false; 2105 } 2106 } 2107 2108 break; 2109 } 2110 } 2111 2112 if (!found_range) { 2113 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2114 /* dev */ 0, __LINE__, SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC", 2115 "Push constant range covering variable starting at " 2116 "offset %u not declared in layout", 2117 offset)) { 2118 pass = false; 2119 } 2120 } 2121 } 2122 } 2123 } 2124 2125 return pass; 2126} 2127 2128static bool validate_push_constant_usage(layer_data *my_data, VkDevice dev, 2129 std::vector<VkPushConstantRange> const *pushConstantRanges, shader_module const *src, 2130 std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) { 2131 bool pass = true; 2132 2133 for (auto id : accessible_ids) { 2134 auto def_insn = src->get_def(id); 2135 if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) { 2136 pass = validate_push_constant_block_against_pipeline(my_data, dev, pushConstantRanges, src, 2137 src->get_def(def_insn.word(1)), stage) && 2138 pass; 2139 } 2140 } 2141 2142 return pass; 2143} 2144 2145// For given pipelineLayout verify that the setLayout at slot.first 2146// has the requested binding at slot.second 2147static bool has_descriptor_binding(layer_data *my_data, vector<VkDescriptorSetLayout> *pipelineLayout, descriptor_slot_t slot, 2148 VkDescriptorType &type, VkShaderStageFlags &stage_flags) { 2149 type = VkDescriptorType(0); 2150 stage_flags = VkShaderStageFlags(0); 2151 2152 if (!pipelineLayout) 2153 return false; 2154 2155 if (slot.first >= pipelineLayout->size()) 2156 return false; 2157 2158 auto const layout_node = my_data->descriptorSetLayoutMap[(*pipelineLayout)[slot.first]]; 2159 2160 auto bindingIt = layout_node->bindingToIndexMap.find(slot.second); 2161 if ((bindingIt == layout_node->bindingToIndexMap.end()) || (layout_node->createInfo.pBindings == NULL)) 2162 return false; 2163 2164 assert(bindingIt->second < layout_node->createInfo.bindingCount); 2165 VkDescriptorSetLayoutBinding binding = layout_node->createInfo.pBindings[bindingIt->second]; 2166 type = binding.descriptorType; 2167 stage_flags = binding.stageFlags; 2168 2169 return true; 2170} 2171 2172// Block of code at start here for managing/tracking Pipeline state that this layer cares about 2173 2174static uint64_t g_drawCount[NUM_DRAW_TYPES] = {0, 0, 0, 0}; 2175 2176// TODO : Should be tracking lastBound per commandBuffer and when draws occur, report based on that cmd buffer lastBound 2177// Then need to synchronize the accesses based on cmd buffer so that if I'm reading state on one cmd buffer, updates 2178// to that same cmd buffer by separate thread are not changing state from underneath us 2179// Track the last cmd buffer touched by this thread 2180 2181// prototype 2182static GLOBAL_CB_NODE *getCBNode(layer_data *, const VkCommandBuffer); 2183 2184static VkBool32 hasDrawCmd(GLOBAL_CB_NODE *pCB) { 2185 for (uint32_t i = 0; i < NUM_DRAW_TYPES; i++) { 2186 if (pCB->drawCount[i]) 2187 return VK_TRUE; 2188 } 2189 return VK_FALSE; 2190} 2191 2192// Check object status for selected flag state 2193static VkBool32 validate_status(layer_data *my_data, GLOBAL_CB_NODE *pNode, CBStatusFlags enable_mask, CBStatusFlags status_mask, 2194 CBStatusFlags status_flag, VkFlags msg_flags, DRAW_STATE_ERROR error_code, const char *fail_msg) { 2195 // If non-zero enable mask is present, check it against status but if enable_mask 2196 // is 0 then no enable required so we should always just check status 2197 if ((!enable_mask) || (enable_mask & pNode->status)) { 2198 if ((pNode->status & status_mask) != status_flag) { 2199 // TODO : How to pass dispatchable objects as srcObject? Here src obj should be cmd buffer 2200 return log_msg(my_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, error_code, 2201 "DS", "CB object %#" PRIxLEAST64 ": %s", (uint64_t)(pNode->commandBuffer), fail_msg); 2202 } 2203 } 2204 return VK_FALSE; 2205} 2206 2207// Retrieve pipeline node ptr for given pipeline object 2208static PIPELINE_NODE *getPipeline(layer_data *my_data, const VkPipeline pipeline) { 2209 if (my_data->pipelineMap.find(pipeline) == my_data->pipelineMap.end()) { 2210 return NULL; 2211 } 2212 return my_data->pipelineMap[pipeline]; 2213} 2214 2215// Return VK_TRUE if for a given PSO, the given state enum is dynamic, else return VK_FALSE 2216static VkBool32 isDynamic(const PIPELINE_NODE *pPipeline, const VkDynamicState state) { 2217 if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) { 2218 for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) { 2219 if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) 2220 return VK_TRUE; 2221 } 2222 } 2223 return VK_FALSE; 2224} 2225 2226// Validate state stored as flags at time of draw call 2227static VkBool32 validate_draw_state_flags(layer_data *my_data, GLOBAL_CB_NODE *pCB, VkBool32 indexedDraw) { 2228 VkBool32 result; 2229 result = 2230 validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_VIEWPORT_SET, CBSTATUS_VIEWPORT_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2231 DRAWSTATE_VIEWPORT_NOT_BOUND, "Dynamic viewport state not set for this command buffer"); 2232 result |= 2233 validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_SCISSOR_SET, CBSTATUS_SCISSOR_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2234 DRAWSTATE_SCISSOR_NOT_BOUND, "Dynamic scissor state not set for this command buffer"); 2235 result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_LINE_WIDTH_SET, CBSTATUS_LINE_WIDTH_SET, 2236 VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_LINE_WIDTH_NOT_BOUND, 2237 "Dynamic line width state not set for this command buffer"); 2238 result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_DEPTH_BIAS_SET, CBSTATUS_DEPTH_BIAS_SET, 2239 VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_DEPTH_BIAS_NOT_BOUND, 2240 "Dynamic depth bias state not set for this command buffer"); 2241 result |= validate_status(my_data, pCB, CBSTATUS_COLOR_BLEND_WRITE_ENABLE, CBSTATUS_BLEND_SET, CBSTATUS_BLEND_SET, 2242 VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_BLEND_NOT_BOUND, 2243 "Dynamic blend object state not set for this command buffer"); 2244 result |= validate_status(my_data, pCB, CBSTATUS_DEPTH_WRITE_ENABLE, CBSTATUS_DEPTH_BOUNDS_SET, CBSTATUS_DEPTH_BOUNDS_SET, 2245 VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_DEPTH_BOUNDS_NOT_BOUND, 2246 "Dynamic depth bounds state not set for this command buffer"); 2247 result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_READ_MASK_SET, 2248 CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND, 2249 "Dynamic stencil read mask state not set for this command buffer"); 2250 result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_WRITE_MASK_SET, 2251 CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND, 2252 "Dynamic stencil write mask state not set for this command buffer"); 2253 result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_REFERENCE_SET, 2254 CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND, 2255 "Dynamic stencil reference state not set for this command buffer"); 2256 if (indexedDraw) 2257 result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_INDEX_BUFFER_BOUND, CBSTATUS_INDEX_BUFFER_BOUND, 2258 VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_INDEX_BUFFER_NOT_BOUND, 2259 "Index buffer object not bound to this command buffer when Indexed Draw attempted"); 2260 return result; 2261} 2262 2263// Verify attachment reference compatibility according to spec 2264// If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this 2265// If both AttachmentReference arrays have requested index, check their corresponding AttachementDescriptions 2266// to make sure that format and samples counts match. 2267// If not, they are not compatible. 2268static bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary, 2269 const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments, 2270 const VkAttachmentReference *pSecondary, const uint32_t secondaryCount, 2271 const VkAttachmentDescription *pSecondaryAttachments) { 2272 if (index >= primaryCount) { // Check secondary as if primary is VK_ATTACHMENT_UNUSED 2273 if (VK_ATTACHMENT_UNUSED != pSecondary[index].attachment) 2274 return false; 2275 } else if (index >= secondaryCount) { // Check primary as if secondary is VK_ATTACHMENT_UNUSED 2276 if (VK_ATTACHMENT_UNUSED != pPrimary[index].attachment) 2277 return false; 2278 } else { // format and sample count must match 2279 if ((pPrimaryAttachments[pPrimary[index].attachment].format == 2280 pSecondaryAttachments[pSecondary[index].attachment].format) && 2281 (pPrimaryAttachments[pPrimary[index].attachment].samples == 2282 pSecondaryAttachments[pSecondary[index].attachment].samples)) 2283 return true; 2284 } 2285 // Format and sample counts didn't match 2286 return false; 2287} 2288 2289// For give primary and secondary RenderPass objects, verify that they're compatible 2290static bool verify_renderpass_compatibility(layer_data *my_data, const VkRenderPass primaryRP, const VkRenderPass secondaryRP, 2291 string &errorMsg) { 2292 stringstream errorStr; 2293 if (my_data->renderPassMap.find(primaryRP) == my_data->renderPassMap.end()) { 2294 errorStr << "invalid VkRenderPass (" << primaryRP << ")"; 2295 errorMsg = errorStr.str(); 2296 return false; 2297 } else if (my_data->renderPassMap.find(secondaryRP) == my_data->renderPassMap.end()) { 2298 errorStr << "invalid VkRenderPass (" << secondaryRP << ")"; 2299 errorMsg = errorStr.str(); 2300 return false; 2301 } 2302 // Trivial pass case is exact same RP 2303 if (primaryRP == secondaryRP) { 2304 return true; 2305 } 2306 const VkRenderPassCreateInfo *primaryRPCI = my_data->renderPassMap[primaryRP]->pCreateInfo; 2307 const VkRenderPassCreateInfo *secondaryRPCI = my_data->renderPassMap[secondaryRP]->pCreateInfo; 2308 if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) { 2309 errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount 2310 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses."; 2311 errorMsg = errorStr.str(); 2312 return false; 2313 } 2314 uint32_t spIndex = 0; 2315 for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) { 2316 // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible 2317 uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount; 2318 uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount; 2319 uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount); 2320 for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) { 2321 if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount, 2322 primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments, 2323 secondaryColorCount, secondaryRPCI->pAttachments)) { 2324 errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible."; 2325 errorMsg = errorStr.str(); 2326 return false; 2327 } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments, 2328 primaryColorCount, primaryRPCI->pAttachments, 2329 secondaryRPCI->pSubpasses[spIndex].pResolveAttachments, 2330 secondaryColorCount, secondaryRPCI->pAttachments)) { 2331 errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible."; 2332 errorMsg = errorStr.str(); 2333 return false; 2334 } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 2335 primaryColorCount, primaryRPCI->pAttachments, 2336 secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 2337 secondaryColorCount, secondaryRPCI->pAttachments)) { 2338 errorStr << "depth/stencil attachments at index " << cIdx << " of subpass index " << spIndex 2339 << " are not compatible."; 2340 errorMsg = errorStr.str(); 2341 return false; 2342 } 2343 } 2344 uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount; 2345 uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount; 2346 uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount); 2347 for (uint32_t i = 0; i < inputMax; ++i) { 2348 if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryColorCount, 2349 primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments, 2350 secondaryColorCount, secondaryRPCI->pAttachments)) { 2351 errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible."; 2352 errorMsg = errorStr.str(); 2353 return false; 2354 } 2355 } 2356 } 2357 return true; 2358} 2359 2360// For give SET_NODE, verify that its Set is compatible w/ the setLayout corresponding to pipelineLayout[layoutIndex] 2361static bool verify_set_layout_compatibility(layer_data *my_data, const SET_NODE *pSet, const VkPipelineLayout layout, 2362 const uint32_t layoutIndex, string &errorMsg) { 2363 stringstream errorStr; 2364 if (my_data->pipelineLayoutMap.find(layout) == my_data->pipelineLayoutMap.end()) { 2365 errorStr << "invalid VkPipelineLayout (" << layout << ")"; 2366 errorMsg = errorStr.str(); 2367 return false; 2368 } 2369 PIPELINE_LAYOUT_NODE pl = my_data->pipelineLayoutMap[layout]; 2370 if (layoutIndex >= pl.descriptorSetLayouts.size()) { 2371 errorStr << "VkPipelineLayout (" << layout << ") only contains " << pl.descriptorSetLayouts.size() 2372 << " setLayouts corresponding to sets 0-" << pl.descriptorSetLayouts.size() - 1 2373 << ", but you're attempting to bind set to index " << layoutIndex; 2374 errorMsg = errorStr.str(); 2375 return false; 2376 } 2377 // Get the specific setLayout from PipelineLayout that overlaps this set 2378 LAYOUT_NODE *pLayoutNode = my_data->descriptorSetLayoutMap[pl.descriptorSetLayouts[layoutIndex]]; 2379 if (pLayoutNode->layout == pSet->pLayout->layout) { // trivial pass case 2380 return true; 2381 } 2382 size_t descriptorCount = pLayoutNode->descriptorTypes.size(); 2383 if (descriptorCount != pSet->pLayout->descriptorTypes.size()) { 2384 errorStr << "setLayout " << layoutIndex << " from pipelineLayout " << layout << " has " << descriptorCount 2385 << " descriptors, but corresponding set being bound has " << pSet->pLayout->descriptorTypes.size() 2386 << " descriptors."; 2387 errorMsg = errorStr.str(); 2388 return false; // trivial fail case 2389 } 2390 // Now need to check set against corresponding pipelineLayout to verify compatibility 2391 for (size_t i = 0; i < descriptorCount; ++i) { 2392 // Need to verify that layouts are identically defined 2393 // TODO : Is below sufficient? Making sure that types & stageFlags match per descriptor 2394 // do we also need to check immutable samplers? 2395 if (pLayoutNode->descriptorTypes[i] != pSet->pLayout->descriptorTypes[i]) { 2396 errorStr << "descriptor " << i << " for descriptorSet being bound is type '" 2397 << string_VkDescriptorType(pSet->pLayout->descriptorTypes[i]) 2398 << "' but corresponding descriptor from pipelineLayout is type '" 2399 << string_VkDescriptorType(pLayoutNode->descriptorTypes[i]) << "'"; 2400 errorMsg = errorStr.str(); 2401 return false; 2402 } 2403 if (pLayoutNode->stageFlags[i] != pSet->pLayout->stageFlags[i]) { 2404 errorStr << "stageFlags " << i << " for descriptorSet being bound is " << pSet->pLayout->stageFlags[i] 2405 << "' but corresponding descriptor from pipelineLayout has stageFlags " << pLayoutNode->stageFlags[i]; 2406 errorMsg = errorStr.str(); 2407 return false; 2408 } 2409 } 2410 return true; 2411} 2412 2413// Validate that data for each specialization entry is fully contained within the buffer. 2414static VkBool32 validate_specialization_offsets(layer_data *my_data, VkPipelineShaderStageCreateInfo const *info) { 2415 VkBool32 pass = VK_TRUE; 2416 2417 VkSpecializationInfo const *spec = info->pSpecializationInfo; 2418 2419 if (spec) { 2420 for (auto i = 0u; i < spec->mapEntryCount; i++) { 2421 if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) { 2422 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2423 /*dev*/ 0, __LINE__, SHADER_CHECKER_BAD_SPECIALIZATION, "SC", 2424 "Specialization entry %u (for constant id %u) references memory outside provided " 2425 "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER 2426 " bytes provided)", 2427 i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset, 2428 spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize)) { 2429 2430 pass = VK_FALSE; 2431 } 2432 } 2433 } 2434 } 2435 2436 return pass; 2437} 2438 2439static bool descriptor_type_match(layer_data *my_data, shader_module const *module, uint32_t type_id, 2440 VkDescriptorType descriptor_type) { 2441 auto type = module->get_def(type_id); 2442 2443 /* Strip off any array or ptrs */ 2444 /* TODO: if we see an array type here, we should make use of it in order to 2445 * validate the number of descriptors actually required to be set in the 2446 * API. 2447 */ 2448 while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) { 2449 type = module->get_def(type.word(type.opcode() == spv::OpTypeArray ? 2 : 3)); 2450 } 2451 2452 switch (type.opcode()) { 2453 case spv::OpTypeStruct: { 2454 for (auto insn : *module) { 2455 if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) { 2456 if (insn.word(2) == spv::DecorationBlock) { 2457 return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || 2458 descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 2459 } else if (insn.word(2) == spv::DecorationBufferBlock) { 2460 return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || 2461 descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; 2462 } 2463 } 2464 } 2465 2466 /* Invalid */ 2467 return false; 2468 } 2469 2470 case spv::OpTypeSampler: 2471 return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER; 2472 2473 case spv::OpTypeSampledImage: 2474 return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 2475 2476 case spv::OpTypeImage: { 2477 /* Many descriptor types backing image types-- depends on dimension 2478 * and whether the image will be used with a sampler. SPIRV for 2479 * Vulkan requires that sampled be 1 or 2 -- leaving the decision to 2480 * runtime is unacceptable. 2481 */ 2482 auto dim = type.word(3); 2483 auto sampled = type.word(7); 2484 2485 if (dim == spv::DimSubpassData) { 2486 return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; 2487 } else if (dim == spv::DimBuffer) { 2488 if (sampled == 1) { 2489 return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; 2490 } else { 2491 return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; 2492 } 2493 } else if (sampled == 1) { 2494 return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; 2495 } else { 2496 return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; 2497 } 2498 } 2499 2500 /* We shouldn't really see any other junk types -- but if we do, they're 2501 * a mismatch. 2502 */ 2503 default: 2504 return false; /* Mismatch */ 2505 } 2506} 2507 2508static VkBool32 require_feature(layer_data *my_data, VkBool32 feature, char const *feature_name) { 2509 if (!feature) { 2510 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2511 /* dev */ 0, __LINE__, SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC", 2512 "Shader requires VkPhysicalDeviceFeatures::%s but is not " 2513 "enabled on the device", 2514 feature_name)) { 2515 return false; 2516 } 2517 } 2518 2519 return true; 2520} 2521 2522static VkBool32 validate_shader_capabilities(layer_data *my_data, VkDevice dev, shader_module const *src) 2523{ 2524 VkBool32 pass = VK_TRUE; 2525 2526 auto enabledFeatures = &my_data->physDevProperties.features; 2527 2528 for (auto insn : *src) { 2529 if (insn.opcode() == spv::OpCapability) { 2530 switch (insn.word(1)) { 2531 case spv::CapabilityMatrix: 2532 case spv::CapabilityShader: 2533 case spv::CapabilityInputAttachment: 2534 case spv::CapabilitySampled1D: 2535 case spv::CapabilityImage1D: 2536 case spv::CapabilitySampledBuffer: 2537 case spv::CapabilityImageBuffer: 2538 case spv::CapabilityImageQuery: 2539 case spv::CapabilityDerivativeControl: 2540 // Always supported by a Vulkan 1.0 implementation -- no feature bits. 2541 break; 2542 2543 case spv::CapabilityGeometry: 2544 pass &= require_feature(my_data, enabledFeatures->geometryShader, "geometryShader"); 2545 break; 2546 2547 case spv::CapabilityTessellation: 2548 pass &= require_feature(my_data, enabledFeatures->tessellationShader, "tessellationShader"); 2549 break; 2550 2551 case spv::CapabilityFloat64: 2552 pass &= require_feature(my_data, enabledFeatures->shaderFloat64, "shaderFloat64"); 2553 break; 2554 2555 case spv::CapabilityInt64: 2556 pass &= require_feature(my_data, enabledFeatures->shaderInt64, "shaderInt64"); 2557 break; 2558 2559 case spv::CapabilityTessellationPointSize: 2560 case spv::CapabilityGeometryPointSize: 2561 pass &= require_feature(my_data, enabledFeatures->shaderTessellationAndGeometryPointSize, 2562 "shaderTessellationAndGeometryPointSize"); 2563 break; 2564 2565 case spv::CapabilityImageGatherExtended: 2566 pass &= require_feature(my_data, enabledFeatures->shaderImageGatherExtended, "shaderImageGatherExtended"); 2567 break; 2568 2569 case spv::CapabilityStorageImageMultisample: 2570 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageMultisample, "shaderStorageImageMultisample"); 2571 break; 2572 2573 case spv::CapabilityUniformBufferArrayDynamicIndexing: 2574 pass &= require_feature(my_data, enabledFeatures->shaderUniformBufferArrayDynamicIndexing, 2575 "shaderUniformBufferArrayDynamicIndexing"); 2576 break; 2577 2578 case spv::CapabilitySampledImageArrayDynamicIndexing: 2579 pass &= require_feature(my_data, enabledFeatures->shaderSampledImageArrayDynamicIndexing, 2580 "shaderSampledImageArrayDynamicIndexing"); 2581 break; 2582 2583 case spv::CapabilityStorageBufferArrayDynamicIndexing: 2584 pass &= require_feature(my_data, enabledFeatures->shaderStorageBufferArrayDynamicIndexing, 2585 "shaderStorageBufferArrayDynamicIndexing"); 2586 break; 2587 2588 case spv::CapabilityStorageImageArrayDynamicIndexing: 2589 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageArrayDynamicIndexing, 2590 "shaderStorageImageArrayDynamicIndexing"); 2591 break; 2592 2593 case spv::CapabilityClipDistance: 2594 pass &= require_feature(my_data, enabledFeatures->shaderClipDistance, "shaderClipDistance"); 2595 break; 2596 2597 case spv::CapabilityCullDistance: 2598 pass &= require_feature(my_data, enabledFeatures->shaderCullDistance, "shaderCullDistance"); 2599 break; 2600 2601 case spv::CapabilityImageCubeArray: 2602 pass &= require_feature(my_data, enabledFeatures->imageCubeArray, "imageCubeArray"); 2603 break; 2604 2605 case spv::CapabilitySampleRateShading: 2606 pass &= require_feature(my_data, enabledFeatures->sampleRateShading, "sampleRateShading"); 2607 break; 2608 2609 case spv::CapabilitySparseResidency: 2610 pass &= require_feature(my_data, enabledFeatures->shaderResourceResidency, "shaderResourceResidency"); 2611 break; 2612 2613 case spv::CapabilityMinLod: 2614 pass &= require_feature(my_data, enabledFeatures->shaderResourceMinLod, "shaderResourceMinLod"); 2615 break; 2616 2617 case spv::CapabilitySampledCubeArray: 2618 pass &= require_feature(my_data, enabledFeatures->imageCubeArray, "imageCubeArray"); 2619 break; 2620 2621 case spv::CapabilityImageMSArray: 2622 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageMultisample, "shaderStorageImageMultisample"); 2623 break; 2624 2625 case spv::CapabilityStorageImageExtendedFormats: 2626 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageExtendedFormats, 2627 "shaderStorageImageExtendedFormats"); 2628 break; 2629 2630 case spv::CapabilityInterpolationFunction: 2631 pass &= require_feature(my_data, enabledFeatures->sampleRateShading, "sampleRateShading"); 2632 break; 2633 2634 case spv::CapabilityStorageImageReadWithoutFormat: 2635 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageReadWithoutFormat, 2636 "shaderStorageImageReadWithoutFormat"); 2637 break; 2638 2639 case spv::CapabilityStorageImageWriteWithoutFormat: 2640 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageWriteWithoutFormat, 2641 "shaderStorageImageWriteWithoutFormat"); 2642 break; 2643 2644 case spv::CapabilityMultiViewport: 2645 pass &= require_feature(my_data, enabledFeatures->multiViewport, "multiViewport"); 2646 break; 2647 2648 default: 2649 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /* dev */0, 2650 __LINE__, SHADER_CHECKER_BAD_CAPABILITY, "SC", 2651 "Shader declares capability %u, not supported in Vulkan.", 2652 insn.word(1))) 2653 pass = VK_FALSE; 2654 break; 2655 } 2656 } 2657 } 2658 2659 return pass; 2660} 2661 2662 2663// Validate that the shaders used by the given pipeline 2664// As a side effect this function also records the sets that are actually used by the pipeline 2665static VkBool32 validate_pipeline_shaders(layer_data *my_data, VkDevice dev, PIPELINE_NODE *pPipeline) { 2666 VkGraphicsPipelineCreateInfo const *pCreateInfo = &pPipeline->graphicsPipelineCI; 2667 /* We seem to allow pipeline stages to be specified out of order, so collect and identify them 2668 * before trying to do anything more: */ 2669 int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT); 2670 int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT); 2671 2672 shader_module *shaders[5]; 2673 memset(shaders, 0, sizeof(shaders)); 2674 spirv_inst_iter entrypoints[5]; 2675 memset(entrypoints, 0, sizeof(entrypoints)); 2676 RENDER_PASS_NODE const *rp = 0; 2677 VkPipelineVertexInputStateCreateInfo const *vi = 0; 2678 VkBool32 pass = VK_TRUE; 2679 2680 for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { 2681 VkPipelineShaderStageCreateInfo const *pStage = &pCreateInfo->pStages[i]; 2682 if (pStage->sType == VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO) { 2683 2684 if ((pStage->stage & (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | 2685 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) == 0) { 2686 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2687 /*dev*/ 0, __LINE__, SHADER_CHECKER_UNKNOWN_STAGE, "SC", "Unknown shader stage %d", pStage->stage)) { 2688 pass = VK_FALSE; 2689 } 2690 } else { 2691 pass = validate_specialization_offsets(my_data, pStage) && pass; 2692 2693 auto stage_id = get_shader_stage_id(pStage->stage); 2694 shader_module *module = my_data->shaderModuleMap[pStage->module]; 2695 shaders[stage_id] = module; 2696 2697 /* find the entrypoint */ 2698 entrypoints[stage_id] = find_entrypoint(module, pStage->pName, pStage->stage); 2699 if (entrypoints[stage_id] == module->end()) { 2700 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2701 /*dev*/ 0, __LINE__, SHADER_CHECKER_MISSING_ENTRYPOINT, "SC", 2702 "No entrypoint found named `%s` for stage %s", pStage->pName, 2703 string_VkShaderStageFlagBits(pStage->stage))) { 2704 pass = VK_FALSE; 2705 } 2706 } 2707 2708 /* validate shader capabilities against enabled device features */ 2709 pass = validate_shader_capabilities(my_data, dev, module) && pass; 2710 2711 /* mark accessible ids */ 2712 std::unordered_set<uint32_t> accessible_ids; 2713 mark_accessible_ids(module, entrypoints[stage_id], accessible_ids); 2714 2715 /* validate descriptor set layout against what the entrypoint actually uses */ 2716 std::map<descriptor_slot_t, interface_var> descriptor_uses; 2717 collect_interface_by_descriptor_slot(my_data, dev, module, accessible_ids, descriptor_uses); 2718 2719 auto layouts = pCreateInfo->layout != VK_NULL_HANDLE 2720 ? &(my_data->pipelineLayoutMap[pCreateInfo->layout].descriptorSetLayouts) 2721 : nullptr; 2722 2723 for (auto it = descriptor_uses.begin(); it != descriptor_uses.end(); it++) { 2724 // As a side-effect of this function, capture which sets are used by the pipeline 2725 pPipeline->active_sets.insert(it->first.first); 2726 2727 /* find the matching binding */ 2728 VkDescriptorType descriptor_type; 2729 VkShaderStageFlags descriptor_stage_flags; 2730 auto found = has_descriptor_binding(my_data, layouts, it->first, descriptor_type, descriptor_stage_flags); 2731 2732 if (!found) { 2733 char type_name[1024]; 2734 describe_type(type_name, module, it->second.type_id); 2735 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2736 /*dev*/ 0, __LINE__, SHADER_CHECKER_MISSING_DESCRIPTOR, "SC", 2737 "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout", 2738 it->first.first, it->first.second, type_name)) { 2739 pass = VK_FALSE; 2740 } 2741 } else if (~descriptor_stage_flags & pStage->stage) { 2742 char type_name[1024]; 2743 describe_type(type_name, module, it->second.type_id); 2744 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2745 /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC", 2746 "Shader uses descriptor slot %u.%u (used " 2747 "as type `%s`) but descriptor not " 2748 "accessible from stage %s", 2749 it->first.first, it->first.second, type_name, string_VkShaderStageFlagBits(pStage->stage))) { 2750 pass = VK_FALSE; 2751 } 2752 } else if (!descriptor_type_match(my_data, module, it->second.type_id, descriptor_type)) { 2753 char type_name[1024]; 2754 describe_type(type_name, module, it->second.type_id); 2755 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 2756 /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC", 2757 "Type mismatch on descriptor slot " 2758 "%u.%u (used as type `%s`) but " 2759 "descriptor of type %s", 2760 it->first.first, it->first.second, type_name, string_VkDescriptorType(descriptor_type))) { 2761 pass = VK_FALSE; 2762 } 2763 } 2764 } 2765 2766 /* validate push constant usage */ 2767 pass = 2768 validate_push_constant_usage(my_data, dev, &my_data->pipelineLayoutMap[pCreateInfo->layout].pushConstantRanges, 2769 module, accessible_ids, pStage->stage) && 2770 pass; 2771 } 2772 } 2773 } 2774 2775 if (pCreateInfo->renderPass != VK_NULL_HANDLE) 2776 rp = my_data->renderPassMap[pCreateInfo->renderPass]; 2777 2778 vi = pCreateInfo->pVertexInputState; 2779 2780 if (vi) { 2781 pass = validate_vi_consistency(my_data, dev, vi) && pass; 2782 } 2783 2784 if (shaders[vertex_stage]) { 2785 pass = validate_vi_against_vs_inputs(my_data, dev, vi, shaders[vertex_stage], entrypoints[vertex_stage]) && pass; 2786 } 2787 2788 /* TODO: enforce rules about present combinations of shaders */ 2789 int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT); 2790 int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); 2791 2792 while (!shaders[producer] && producer != fragment_stage) { 2793 producer++; 2794 consumer++; 2795 } 2796 2797 for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) { 2798 assert(shaders[producer]); 2799 if (shaders[consumer]) { 2800 pass = validate_interface_between_stages(my_data, dev, shaders[producer], entrypoints[producer], 2801 shader_stage_attribs[producer].name, shaders[consumer], entrypoints[consumer], 2802 shader_stage_attribs[consumer].name, 2803 shader_stage_attribs[consumer].arrayed_input) && 2804 pass; 2805 2806 producer = consumer; 2807 } 2808 } 2809 2810 if (shaders[fragment_stage] && rp) { 2811 pass = validate_fs_outputs_against_render_pass(my_data, dev, shaders[fragment_stage], entrypoints[fragment_stage], rp, 2812 pCreateInfo->subpass) && 2813 pass; 2814 } 2815 2816 return pass; 2817} 2818 2819// Return Set node ptr for specified set or else NULL 2820static SET_NODE *getSetNode(layer_data *my_data, const VkDescriptorSet set) { 2821 if (my_data->setMap.find(set) == my_data->setMap.end()) { 2822 return NULL; 2823 } 2824 return my_data->setMap[set]; 2825} 2826// For the given command buffer, verify that for each set set in activeSetNodes 2827// that any dynamic descriptor in that set has a valid dynamic offset bound. 2828// To be valid, the dynamic offset combined with the offet and range from its 2829// descriptor update must not overflow the size of its buffer being updated 2830static VkBool32 validate_dynamic_offsets(layer_data *my_data, const GLOBAL_CB_NODE *pCB, const vector<SET_NODE *> activeSetNodes) { 2831 VkBool32 result = VK_FALSE; 2832 2833 VkWriteDescriptorSet *pWDS = NULL; 2834 uint32_t dynOffsetIndex = 0; 2835 VkDeviceSize bufferSize = 0; 2836 for (auto set_node : activeSetNodes) { 2837 for (uint32_t i = 0; i < set_node->descriptorCount; ++i) { 2838 // TODO: Add validation for descriptors dynamically skipped in shader 2839 if (set_node->ppDescriptors[i] != NULL) { 2840 switch (set_node->ppDescriptors[i]->sType) { 2841 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 2842 pWDS = (VkWriteDescriptorSet *)set_node->ppDescriptors[i]; 2843 if ((pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) || 2844 (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) { 2845 for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) { 2846 bufferSize = my_data->bufferMap[pWDS->pBufferInfo[j].buffer].create_info->size; 2847 if (pWDS->pBufferInfo[j].range == VK_WHOLE_SIZE) { 2848 if ((pCB->dynamicOffsets[dynOffsetIndex] + pWDS->pBufferInfo[j].offset) > bufferSize) { 2849 result |= 2850 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2851 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)set_node->set, __LINE__, 2852 DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS", 2853 "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has range of " 2854 "VK_WHOLE_SIZE but dynamic offset %u " 2855 "combined with offet %#" PRIxLEAST64 " oversteps its buffer (%#" PRIxLEAST64 2856 ") which has a size of %#" PRIxLEAST64 ".", 2857 (uint64_t)set_node->set, i, pCB->dynamicOffsets[dynOffsetIndex], 2858 pWDS->pBufferInfo[j].offset, (uint64_t)pWDS->pBufferInfo[j].buffer, bufferSize); 2859 } 2860 } else if ((pCB->dynamicOffsets[dynOffsetIndex] + pWDS->pBufferInfo[j].offset + 2861 pWDS->pBufferInfo[j].range) > bufferSize) { 2862 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2863 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)set_node->set, __LINE__, 2864 DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS", 2865 "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has dynamic offset %u. " 2866 "Combined with offet %#" PRIxLEAST64 " and range %#" PRIxLEAST64 2867 " from its update, this oversteps its buffer " 2868 "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".", 2869 (uint64_t)set_node->set, i, pCB->dynamicOffsets[dynOffsetIndex], 2870 pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range, 2871 (uint64_t)pWDS->pBufferInfo[j].buffer, bufferSize); 2872 } else if ((pCB->dynamicOffsets[dynOffsetIndex] + pWDS->pBufferInfo[j].offset + 2873 pWDS->pBufferInfo[j].range) > bufferSize) { 2874 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2875 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)set_node->set, __LINE__, 2876 DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS", 2877 "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has dynamic offset %u. " 2878 "Combined with offet %#" PRIxLEAST64 " and range %#" PRIxLEAST64 2879 " from its update, this oversteps its buffer " 2880 "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".", 2881 (uint64_t)set_node->set, i, pCB->dynamicOffsets[dynOffsetIndex], 2882 pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range, 2883 (uint64_t)pWDS->pBufferInfo[j].buffer, bufferSize); 2884 } 2885 dynOffsetIndex++; 2886 i += j; // Advance i to end of this set of descriptors (++i at end of for loop will move 1 index past 2887 // last of these descriptors) 2888 } 2889 } 2890 break; 2891 default: // Currently only shadowing Write update nodes so shouldn't get here 2892 assert(0); 2893 continue; 2894 } 2895 } 2896 } 2897 } 2898 return result; 2899} 2900 2901// Validate overall state at the time of a draw call 2902static VkBool32 validate_draw_state(layer_data *my_data, GLOBAL_CB_NODE *pCB, VkBool32 indexedDraw) { 2903 // First check flag states 2904 VkBool32 result = validate_draw_state_flags(my_data, pCB, indexedDraw); 2905 PIPELINE_NODE *pPipe = getPipeline(my_data, pCB->lastBoundPipeline); 2906 // Now complete other state checks 2907 // TODO : Currently only performing next check if *something* was bound (non-zero last bound) 2908 // There is probably a better way to gate when this check happens, and to know if something *should* have been bound 2909 // We should have that check separately and then gate this check based on that check 2910 if (pPipe) { 2911 if (pCB->lastBoundPipelineLayout) { 2912 string errorString; 2913 // Need a vector (vs. std::set) of active Sets for dynamicOffset validation in case same set bound w/ different offsets 2914 vector<SET_NODE *> activeSetNodes; 2915 for (auto setIndex : pPipe->active_sets) { 2916 // If valid set is not bound throw an error 2917 if ((pCB->boundDescriptorSets.size() <= setIndex) || (!pCB->boundDescriptorSets[setIndex])) { 2918 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 2919 __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS", 2920 "VkPipeline %#" PRIxLEAST64 " uses set #%u but that set is not bound.", 2921 (uint64_t)pPipe->pipeline, setIndex); 2922 } else if (!verify_set_layout_compatibility(my_data, my_data->setMap[pCB->boundDescriptorSets[setIndex]], 2923 pPipe->graphicsPipelineCI.layout, setIndex, errorString)) { 2924 // Set is bound but not compatible w/ overlapping pipelineLayout from PSO 2925 VkDescriptorSet setHandle = my_data->setMap[pCB->boundDescriptorSets[setIndex]]->set; 2926 result |= log_msg( 2927 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 2928 (uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS", 2929 "VkDescriptorSet (%#" PRIxLEAST64 2930 ") bound as set #%u is not compatible with overlapping VkPipelineLayout %#" PRIxLEAST64 " due to: %s", 2931 (uint64_t)setHandle, setIndex, (uint64_t)pPipe->graphicsPipelineCI.layout, errorString.c_str()); 2932 } else { // Valid set is bound and layout compatible, validate that it's updated and verify any dynamic offsets 2933 // Pull the set node 2934 SET_NODE *pSet = my_data->setMap[pCB->boundDescriptorSets[setIndex]]; 2935 // Save vector of all active sets to verify dynamicOffsets below 2936 activeSetNodes.push_back(pSet); 2937 // Make sure set has been updated 2938 if (!pSet->pUpdateStructs) { 2939 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 2940 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pSet->set, __LINE__, 2941 DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS", 2942 "DS %#" PRIxLEAST64 " bound but it was never updated. It is now being used to draw so " 2943 "this will result in undefined behavior.", 2944 (uint64_t)pSet->set); 2945 } 2946 } 2947 } 2948 // For each dynamic descriptor, make sure dynamic offset doesn't overstep buffer 2949 if (!pCB->dynamicOffsets.empty()) 2950 result |= validate_dynamic_offsets(my_data, pCB, activeSetNodes); 2951 } 2952 // Verify Vtx binding 2953 if (pPipe->vtxBindingCount > 0) { 2954 VkPipelineVertexInputStateCreateInfo *vtxInCI = &pPipe->vertexInputCI; 2955 for (uint32_t i = 0; i < vtxInCI->vertexBindingDescriptionCount; i++) { 2956 if ((pCB->currentDrawData.buffers.size() < (i + 1)) || (pCB->currentDrawData.buffers[i] == VK_NULL_HANDLE)) { 2957 result |= log_msg( 2958 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 2959 DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS", 2960 "The Pipeline State Object (%#" PRIxLEAST64 2961 ") expects that this Command Buffer's vertex binding Index %d should be set via vkCmdBindVertexBuffers.", 2962 (uint64_t)pCB->lastBoundPipeline, i); 2963 } 2964 } 2965 } else { 2966 if (!pCB->currentDrawData.buffers.empty()) { 2967 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 2968 0, __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS", 2969 "Vertex buffers are bound to command buffer (%#" PRIxLEAST64 2970 ") but no vertex buffers are attached to this Pipeline State Object (%#" PRIxLEAST64 ").", 2971 (uint64_t)pCB->commandBuffer, (uint64_t)pCB->lastBoundPipeline); 2972 } 2973 } 2974 // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count. 2975 // Skip check if rasterization is disabled or there is no viewport. 2976 if ((!pPipe->graphicsPipelineCI.pRasterizationState || 2977 !pPipe->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) && 2978 pPipe->graphicsPipelineCI.pViewportState) { 2979 VkBool32 dynViewport = isDynamic(pPipe, VK_DYNAMIC_STATE_VIEWPORT); 2980 VkBool32 dynScissor = isDynamic(pPipe, VK_DYNAMIC_STATE_SCISSOR); 2981 if (dynViewport) { 2982 if (pCB->viewports.size() != pPipe->graphicsPipelineCI.pViewportState->viewportCount) { 2983 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 2984 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", 2985 "Dynamic viewportCount from vkCmdSetViewport() is " PRINTF_SIZE_T_SPECIFIER 2986 ", but PSO viewportCount is %u. These counts must match.", 2987 pCB->viewports.size(), pPipe->graphicsPipelineCI.pViewportState->viewportCount); 2988 } 2989 } 2990 if (dynScissor) { 2991 if (pCB->scissors.size() != pPipe->graphicsPipelineCI.pViewportState->scissorCount) { 2992 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 2993 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", 2994 "Dynamic scissorCount from vkCmdSetScissor() is " PRINTF_SIZE_T_SPECIFIER 2995 ", but PSO scissorCount is %u. These counts must match.", 2996 pCB->scissors.size(), pPipe->graphicsPipelineCI.pViewportState->scissorCount); 2997 } 2998 } 2999 } 3000 } 3001 return result; 3002} 3003 3004// Verify that create state for a pipeline is valid 3005static VkBool32 verifyPipelineCreateState(layer_data *my_data, const VkDevice device, std::vector<PIPELINE_NODE *> pPipelines, 3006 int pipelineIndex) { 3007 VkBool32 skipCall = VK_FALSE; 3008 3009 PIPELINE_NODE *pPipeline = pPipelines[pipelineIndex]; 3010 3011 // If create derivative bit is set, check that we've specified a base 3012 // pipeline correctly, and that the base pipeline was created to allow 3013 // derivatives. 3014 if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) { 3015 PIPELINE_NODE *pBasePipeline = nullptr; 3016 if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^ 3017 (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) { 3018 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3019 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", 3020 "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified"); 3021 } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) { 3022 if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) { 3023 skipCall |= 3024 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3025 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", 3026 "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline."); 3027 } else { 3028 pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex]; 3029 } 3030 } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) { 3031 pBasePipeline = getPipeline(my_data, pPipeline->graphicsPipelineCI.basePipelineHandle); 3032 } 3033 3034 if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) { 3035 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3036 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", 3037 "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives."); 3038 } 3039 } 3040 3041 if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) { 3042 if (!my_data->physDevProperties.features.independentBlend) { 3043 VkPipelineColorBlendAttachmentState *pAttachments = pPipeline->pAttachments; 3044 for (uint32_t i = 1; i < pPipeline->attachmentCount; i++) { 3045 if ((pAttachments[0].blendEnable != pAttachments[i].blendEnable) || 3046 (pAttachments[0].srcColorBlendFactor != pAttachments[i].srcColorBlendFactor) || 3047 (pAttachments[0].dstColorBlendFactor != pAttachments[i].dstColorBlendFactor) || 3048 (pAttachments[0].colorBlendOp != pAttachments[i].colorBlendOp) || 3049 (pAttachments[0].srcAlphaBlendFactor != pAttachments[i].srcAlphaBlendFactor) || 3050 (pAttachments[0].dstAlphaBlendFactor != pAttachments[i].dstAlphaBlendFactor) || 3051 (pAttachments[0].alphaBlendOp != pAttachments[i].alphaBlendOp) || 3052 (pAttachments[0].colorWriteMask != pAttachments[i].colorWriteMask)) { 3053 skipCall |= 3054 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3055 DRAWSTATE_INDEPENDENT_BLEND, "DS", "Invalid Pipeline CreateInfo: If independent blend feature not " 3056 "enabled, all elements of pAttachments must be identical"); 3057 } 3058 } 3059 } 3060 if (!my_data->physDevProperties.features.logicOp && 3061 (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) { 3062 skipCall |= 3063 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3064 DRAWSTATE_DISABLED_LOGIC_OP, "DS", 3065 "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE"); 3066 } 3067 if ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable == VK_TRUE) && 3068 ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOp < VK_LOGIC_OP_CLEAR) || 3069 (pPipeline->graphicsPipelineCI.pColorBlendState->logicOp > VK_LOGIC_OP_SET))) { 3070 skipCall |= 3071 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3072 DRAWSTATE_INVALID_LOGIC_OP, "DS", 3073 "Invalid Pipeline CreateInfo: If logicOpEnable is VK_TRUE, logicOp must be a valid VkLogicOp value"); 3074 } 3075 } 3076 3077 // Ensure the subpass index is valid. If not, then validate_pipeline_shaders 3078 // produces nonsense errors that confuse users. Other layers should already 3079 // emit errors for renderpass being invalid. 3080 auto rp_data = my_data->renderPassMap.find(pPipeline->graphicsPipelineCI.renderPass); 3081 if (rp_data != my_data->renderPassMap.end() && 3082 pPipeline->graphicsPipelineCI.subpass >= rp_data->second->pCreateInfo->subpassCount) { 3083 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3084 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Subpass index %u " 3085 "is out of range for this renderpass (0..%u)", 3086 pPipeline->graphicsPipelineCI.subpass, rp_data->second->pCreateInfo->subpassCount - 1); 3087 } 3088 3089 if (!validate_pipeline_shaders(my_data, device, pPipeline)) { 3090 skipCall = VK_TRUE; 3091 } 3092 // VS is required 3093 if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) { 3094 skipCall |= 3095 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3096 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Vtx Shader required"); 3097 } 3098 // Either both or neither TC/TE shaders should be defined 3099 if (((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) == 0) != 3100 ((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) == 0)) { 3101 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3102 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", 3103 "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair"); 3104 } 3105 // Compute shaders should be specified independent of Gfx shaders 3106 if ((pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) && 3107 (pPipeline->active_shaders & 3108 (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | 3109 VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT))) { 3110 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3111 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", 3112 "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline"); 3113 } 3114 // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines. 3115 // Mismatching primitive topology and tessellation fails graphics pipeline creation. 3116 if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) && 3117 (pPipeline->iaStateCI.topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) { 3118 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3119 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: " 3120 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA " 3121 "topology for tessellation pipelines"); 3122 } 3123 if (pPipeline->iaStateCI.topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) { 3124 if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) { 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 is only valid for tessellation pipelines"); 3129 } 3130 if (!pPipeline->tessStateCI.patchControlPoints || (pPipeline->tessStateCI.patchControlPoints > 32)) { 3131 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3132 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: " 3133 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive " 3134 "topology used with patchControlPoints value %u." 3135 " patchControlPoints should be >0 and <=32.", 3136 pPipeline->tessStateCI.patchControlPoints); 3137 } 3138 } 3139 // Viewport state must be included if rasterization is enabled. 3140 // If the viewport state is included, the viewport and scissor counts should always match. 3141 // NOTE : Even if these are flagged as dynamic, counts need to be set correctly for shader compiler 3142 if (!pPipeline->graphicsPipelineCI.pRasterizationState || 3143 !pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) { 3144 if (!pPipeline->graphicsPipelineCI.pViewportState) { 3145 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3146 DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "Gfx Pipeline pViewportState is null. Even if viewport " 3147 "and scissors are dynamic PSO must include " 3148 "viewportCount and scissorCount in pViewportState."); 3149 } else if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount != 3150 pPipeline->graphicsPipelineCI.pViewportState->viewportCount) { 3151 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3152 DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", 3153 "Gfx Pipeline viewport count (%u) must match scissor count (%u).", 3154 pPipeline->vpStateCI.viewportCount, pPipeline->vpStateCI.scissorCount); 3155 } else { 3156 // If viewport or scissor are not dynamic, then verify that data is appropriate for count 3157 VkBool32 dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT); 3158 VkBool32 dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR); 3159 if (!dynViewport) { 3160 if (pPipeline->graphicsPipelineCI.pViewportState->viewportCount && 3161 !pPipeline->graphicsPipelineCI.pViewportState->pViewports) { 3162 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 3163 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", 3164 "Gfx Pipeline viewportCount is %u, but pViewports is NULL. For non-zero viewportCount, you " 3165 "must either include pViewports data, or include viewport in pDynamicState and set it with " 3166 "vkCmdSetViewport().", 3167 pPipeline->graphicsPipelineCI.pViewportState->viewportCount); 3168 } 3169 } 3170 if (!dynScissor) { 3171 if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount && 3172 !pPipeline->graphicsPipelineCI.pViewportState->pScissors) { 3173 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 3174 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", 3175 "Gfx Pipeline scissorCount is %u, but pScissors is NULL. For non-zero scissorCount, you " 3176 "must either include pScissors data, or include scissor in pDynamicState and set it with " 3177 "vkCmdSetScissor().", 3178 pPipeline->graphicsPipelineCI.pViewportState->scissorCount); 3179 } 3180 } 3181 } 3182 } 3183 return skipCall; 3184} 3185 3186// Init the pipeline mapping info based on pipeline create info LL tree 3187// Threading note : Calls to this function should wrapped in mutex 3188// TODO : this should really just be in the constructor for PIPELINE_NODE 3189static PIPELINE_NODE *initGraphicsPipeline(layer_data *dev_data, const VkGraphicsPipelineCreateInfo *pCreateInfo) { 3190 PIPELINE_NODE *pPipeline = new PIPELINE_NODE; 3191 3192 // First init create info 3193 memcpy(&pPipeline->graphicsPipelineCI, pCreateInfo, sizeof(VkGraphicsPipelineCreateInfo)); 3194 3195 size_t bufferSize = 0; 3196 const VkPipelineVertexInputStateCreateInfo *pVICI = NULL; 3197 const VkPipelineColorBlendStateCreateInfo *pCBCI = NULL; 3198 3199 for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { 3200 const VkPipelineShaderStageCreateInfo *pPSSCI = &pCreateInfo->pStages[i]; 3201 3202 switch (pPSSCI->stage) { 3203 case VK_SHADER_STAGE_VERTEX_BIT: 3204 memcpy(&pPipeline->vsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); 3205 pPipeline->active_shaders |= VK_SHADER_STAGE_VERTEX_BIT; 3206 break; 3207 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: 3208 memcpy(&pPipeline->tcsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); 3209 pPipeline->active_shaders |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; 3210 break; 3211 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: 3212 memcpy(&pPipeline->tesCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); 3213 pPipeline->active_shaders |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; 3214 break; 3215 case VK_SHADER_STAGE_GEOMETRY_BIT: 3216 memcpy(&pPipeline->gsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); 3217 pPipeline->active_shaders |= VK_SHADER_STAGE_GEOMETRY_BIT; 3218 break; 3219 case VK_SHADER_STAGE_FRAGMENT_BIT: 3220 memcpy(&pPipeline->fsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); 3221 pPipeline->active_shaders |= VK_SHADER_STAGE_FRAGMENT_BIT; 3222 break; 3223 case VK_SHADER_STAGE_COMPUTE_BIT: 3224 // TODO : Flag error, CS is specified through VkComputePipelineCreateInfo 3225 pPipeline->active_shaders |= VK_SHADER_STAGE_COMPUTE_BIT; 3226 break; 3227 default: 3228 // TODO : Flag error 3229 break; 3230 } 3231 } 3232 // Copy over GraphicsPipelineCreateInfo structure embedded pointers 3233 if (pCreateInfo->stageCount != 0) { 3234 pPipeline->graphicsPipelineCI.pStages = new VkPipelineShaderStageCreateInfo[pCreateInfo->stageCount]; 3235 bufferSize = pCreateInfo->stageCount * sizeof(VkPipelineShaderStageCreateInfo); 3236 memcpy((void *)pPipeline->graphicsPipelineCI.pStages, pCreateInfo->pStages, bufferSize); 3237 } 3238 if (pCreateInfo->pVertexInputState != NULL) { 3239 memcpy((void *)&pPipeline->vertexInputCI, pCreateInfo->pVertexInputState, sizeof(VkPipelineVertexInputStateCreateInfo)); 3240 // Copy embedded ptrs 3241 pVICI = pCreateInfo->pVertexInputState; 3242 pPipeline->vtxBindingCount = pVICI->vertexBindingDescriptionCount; 3243 if (pPipeline->vtxBindingCount) { 3244 pPipeline->pVertexBindingDescriptions = new VkVertexInputBindingDescription[pPipeline->vtxBindingCount]; 3245 bufferSize = pPipeline->vtxBindingCount * sizeof(VkVertexInputBindingDescription); 3246 memcpy((void *)pPipeline->pVertexBindingDescriptions, pVICI->pVertexBindingDescriptions, bufferSize); 3247 } 3248 pPipeline->vtxAttributeCount = pVICI->vertexAttributeDescriptionCount; 3249 if (pPipeline->vtxAttributeCount) { 3250 pPipeline->pVertexAttributeDescriptions = new VkVertexInputAttributeDescription[pPipeline->vtxAttributeCount]; 3251 bufferSize = pPipeline->vtxAttributeCount * sizeof(VkVertexInputAttributeDescription); 3252 memcpy((void *)pPipeline->pVertexAttributeDescriptions, pVICI->pVertexAttributeDescriptions, bufferSize); 3253 } 3254 pPipeline->graphicsPipelineCI.pVertexInputState = &pPipeline->vertexInputCI; 3255 } 3256 if (pCreateInfo->pInputAssemblyState != NULL) { 3257 memcpy((void *)&pPipeline->iaStateCI, pCreateInfo->pInputAssemblyState, sizeof(VkPipelineInputAssemblyStateCreateInfo)); 3258 pPipeline->graphicsPipelineCI.pInputAssemblyState = &pPipeline->iaStateCI; 3259 } 3260 if (pCreateInfo->pTessellationState != NULL) { 3261 memcpy((void *)&pPipeline->tessStateCI, pCreateInfo->pTessellationState, sizeof(VkPipelineTessellationStateCreateInfo)); 3262 pPipeline->graphicsPipelineCI.pTessellationState = &pPipeline->tessStateCI; 3263 } 3264 if (pCreateInfo->pViewportState != NULL) { 3265 memcpy((void *)&pPipeline->vpStateCI, pCreateInfo->pViewportState, sizeof(VkPipelineViewportStateCreateInfo)); 3266 pPipeline->graphicsPipelineCI.pViewportState = &pPipeline->vpStateCI; 3267 } 3268 if (pCreateInfo->pRasterizationState != NULL) { 3269 memcpy((void *)&pPipeline->rsStateCI, pCreateInfo->pRasterizationState, sizeof(VkPipelineRasterizationStateCreateInfo)); 3270 pPipeline->graphicsPipelineCI.pRasterizationState = &pPipeline->rsStateCI; 3271 } 3272 if (pCreateInfo->pMultisampleState != NULL) { 3273 memcpy((void *)&pPipeline->msStateCI, pCreateInfo->pMultisampleState, sizeof(VkPipelineMultisampleStateCreateInfo)); 3274 pPipeline->graphicsPipelineCI.pMultisampleState = &pPipeline->msStateCI; 3275 } 3276 if (pCreateInfo->pDepthStencilState != NULL) { 3277 memcpy((void *)&pPipeline->dsStateCI, pCreateInfo->pDepthStencilState, sizeof(VkPipelineDepthStencilStateCreateInfo)); 3278 pPipeline->graphicsPipelineCI.pDepthStencilState = &pPipeline->dsStateCI; 3279 } 3280 if (pCreateInfo->pColorBlendState != NULL) { 3281 memcpy((void *)&pPipeline->cbStateCI, pCreateInfo->pColorBlendState, sizeof(VkPipelineColorBlendStateCreateInfo)); 3282 // Copy embedded ptrs 3283 pCBCI = pCreateInfo->pColorBlendState; 3284 pPipeline->attachmentCount = pCBCI->attachmentCount; 3285 if (pPipeline->attachmentCount) { 3286 pPipeline->pAttachments = new VkPipelineColorBlendAttachmentState[pPipeline->attachmentCount]; 3287 bufferSize = pPipeline->attachmentCount * sizeof(VkPipelineColorBlendAttachmentState); 3288 memcpy((void *)pPipeline->pAttachments, pCBCI->pAttachments, bufferSize); 3289 } 3290 pPipeline->graphicsPipelineCI.pColorBlendState = &pPipeline->cbStateCI; 3291 } 3292 if (pCreateInfo->pDynamicState != NULL) { 3293 memcpy((void *)&pPipeline->dynStateCI, pCreateInfo->pDynamicState, sizeof(VkPipelineDynamicStateCreateInfo)); 3294 if (pPipeline->dynStateCI.dynamicStateCount) { 3295 pPipeline->dynStateCI.pDynamicStates = new VkDynamicState[pPipeline->dynStateCI.dynamicStateCount]; 3296 bufferSize = pPipeline->dynStateCI.dynamicStateCount * sizeof(VkDynamicState); 3297 memcpy((void *)pPipeline->dynStateCI.pDynamicStates, pCreateInfo->pDynamicState->pDynamicStates, bufferSize); 3298 } 3299 pPipeline->graphicsPipelineCI.pDynamicState = &pPipeline->dynStateCI; 3300 } 3301 pPipeline->active_sets.clear(); 3302 return pPipeline; 3303} 3304 3305// Free the Pipeline nodes 3306static void deletePipelines(layer_data *my_data) { 3307 if (my_data->pipelineMap.size() <= 0) 3308 return; 3309 for (auto ii = my_data->pipelineMap.begin(); ii != my_data->pipelineMap.end(); ++ii) { 3310 if ((*ii).second->graphicsPipelineCI.stageCount != 0) { 3311 delete[](*ii).second->graphicsPipelineCI.pStages; 3312 } 3313 delete[](*ii).second->pVertexBindingDescriptions; 3314 delete[](*ii).second->pVertexAttributeDescriptions; 3315 delete[](*ii).second->pAttachments; 3316 if ((*ii).second->dynStateCI.dynamicStateCount != 0) { 3317 delete[](*ii).second->dynStateCI.pDynamicStates; 3318 } 3319 delete (*ii).second; 3320 } 3321 my_data->pipelineMap.clear(); 3322} 3323 3324// For given pipeline, return number of MSAA samples, or one if MSAA disabled 3325static VkSampleCountFlagBits getNumSamples(layer_data *my_data, const VkPipeline pipeline) { 3326 PIPELINE_NODE *pPipe = my_data->pipelineMap[pipeline]; 3327 if (VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pPipe->msStateCI.sType) { 3328 return pPipe->msStateCI.rasterizationSamples; 3329 } 3330 return VK_SAMPLE_COUNT_1_BIT; 3331} 3332 3333// Validate state related to the PSO 3334static VkBool32 validatePipelineState(layer_data *my_data, const GLOBAL_CB_NODE *pCB, const VkPipelineBindPoint pipelineBindPoint, 3335 const VkPipeline pipeline) { 3336 if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) { 3337 // Verify that any MSAA request in PSO matches sample# in bound FB 3338 // Skip the check if rasterization is disabled. 3339 PIPELINE_NODE *pPipeline = my_data->pipelineMap[pipeline]; 3340 if (!pPipeline->graphicsPipelineCI.pRasterizationState || 3341 !pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) { 3342 VkSampleCountFlagBits psoNumSamples = getNumSamples(my_data, pipeline); 3343 if (pCB->activeRenderPass) { 3344 const VkRenderPassCreateInfo *pRPCI = my_data->renderPassMap[pCB->activeRenderPass]->pCreateInfo; 3345 const VkSubpassDescription *pSD = &pRPCI->pSubpasses[pCB->activeSubpass]; 3346 VkSampleCountFlagBits subpassNumSamples = (VkSampleCountFlagBits)0; 3347 uint32_t i; 3348 3349 for (i = 0; i < pSD->colorAttachmentCount; i++) { 3350 VkSampleCountFlagBits samples; 3351 3352 if (pSD->pColorAttachments[i].attachment == VK_ATTACHMENT_UNUSED) 3353 continue; 3354 3355 samples = pRPCI->pAttachments[pSD->pColorAttachments[i].attachment].samples; 3356 if (subpassNumSamples == (VkSampleCountFlagBits)0) { 3357 subpassNumSamples = samples; 3358 } else if (subpassNumSamples != samples) { 3359 subpassNumSamples = (VkSampleCountFlagBits)-1; 3360 break; 3361 } 3362 } 3363 if (pSD->pDepthStencilAttachment && pSD->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { 3364 const VkSampleCountFlagBits samples = pRPCI->pAttachments[pSD->pDepthStencilAttachment->attachment].samples; 3365 if (subpassNumSamples == (VkSampleCountFlagBits)0) 3366 subpassNumSamples = samples; 3367 else if (subpassNumSamples != samples) 3368 subpassNumSamples = (VkSampleCountFlagBits)-1; 3369 } 3370 3371 if (psoNumSamples != subpassNumSamples) { 3372 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, 3373 (uint64_t)pipeline, __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS", 3374 "Num samples mismatch! Binding PSO (%#" PRIxLEAST64 3375 ") with %u samples while current RenderPass (%#" PRIxLEAST64 ") w/ %u samples!", 3376 (uint64_t)pipeline, psoNumSamples, (uint64_t)pCB->activeRenderPass, subpassNumSamples); 3377 } 3378 } else { 3379 // TODO : I believe it's an error if we reach this point and don't have an activeRenderPass 3380 // Verify and flag error as appropriate 3381 } 3382 } 3383 // TODO : Add more checks here 3384 } else { 3385 // TODO : Validate non-gfx pipeline updates 3386 } 3387 return VK_FALSE; 3388} 3389 3390// Block of code at start here specifically for managing/tracking DSs 3391 3392// Return Pool node ptr for specified pool or else NULL 3393static DESCRIPTOR_POOL_NODE *getPoolNode(layer_data *my_data, const VkDescriptorPool pool) { 3394 if (my_data->descriptorPoolMap.find(pool) == my_data->descriptorPoolMap.end()) { 3395 return NULL; 3396 } 3397 return my_data->descriptorPoolMap[pool]; 3398} 3399 3400static LAYOUT_NODE *getLayoutNode(layer_data *my_data, const VkDescriptorSetLayout layout) { 3401 if (my_data->descriptorSetLayoutMap.find(layout) == my_data->descriptorSetLayoutMap.end()) { 3402 return NULL; 3403 } 3404 return my_data->descriptorSetLayoutMap[layout]; 3405} 3406 3407// Return VK_FALSE if update struct is of valid type, otherwise flag error and return code from callback 3408static VkBool32 validUpdateStruct(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) { 3409 switch (pUpdateStruct->sType) { 3410 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 3411 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: 3412 return VK_FALSE; 3413 default: 3414 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3415 DRAWSTATE_INVALID_UPDATE_STRUCT, "DS", 3416 "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", 3417 string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType); 3418 } 3419} 3420 3421// Set count for given update struct in the last parameter 3422// Return value of skipCall, which is only VK_TRUE if error occurs and callback signals execution to cease 3423static uint32_t getUpdateCount(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) { 3424 switch (pUpdateStruct->sType) { 3425 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 3426 return ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorCount; 3427 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: 3428 // TODO : Need to understand this case better and make sure code is correct 3429 return ((VkCopyDescriptorSet *)pUpdateStruct)->descriptorCount; 3430 default: 3431 return 0; 3432 } 3433 return 0; 3434} 3435 3436// For given Layout Node and binding, return index where that binding begins 3437static uint32_t getBindingStartIndex(const LAYOUT_NODE *pLayout, const uint32_t binding) { 3438 uint32_t offsetIndex = 0; 3439 for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) { 3440 if (pLayout->createInfo.pBindings[i].binding == binding) 3441 break; 3442 offsetIndex += pLayout->createInfo.pBindings[i].descriptorCount; 3443 } 3444 return offsetIndex; 3445} 3446 3447// For given layout node and binding, return last index that is updated 3448static uint32_t getBindingEndIndex(const LAYOUT_NODE *pLayout, const uint32_t binding) { 3449 uint32_t offsetIndex = 0; 3450 for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) { 3451 offsetIndex += pLayout->createInfo.pBindings[i].descriptorCount; 3452 if (pLayout->createInfo.pBindings[i].binding == binding) 3453 break; 3454 } 3455 return offsetIndex - 1; 3456} 3457 3458// For given layout and update, return the first overall index of the layout that is updated 3459static uint32_t getUpdateStartIndex(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, const uint32_t binding, 3460 const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) { 3461 return getBindingStartIndex(pLayout, binding) + arrayIndex; 3462} 3463 3464// For given layout and update, return the last overall index of the layout that is updated 3465static uint32_t getUpdateEndIndex(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, const uint32_t binding, 3466 const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) { 3467 uint32_t count = getUpdateCount(my_data, device, pUpdateStruct); 3468 return getBindingStartIndex(pLayout, binding) + arrayIndex + count - 1; 3469} 3470 3471// Verify that the descriptor type in the update struct matches what's expected by the layout 3472static VkBool32 validateUpdateConsistency(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, 3473 const GENERIC_HEADER *pUpdateStruct, uint32_t startIndex, uint32_t endIndex) { 3474 // First get actual type of update 3475 VkBool32 skipCall = VK_FALSE; 3476 VkDescriptorType actualType; 3477 uint32_t i = 0; 3478 switch (pUpdateStruct->sType) { 3479 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 3480 actualType = ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorType; 3481 break; 3482 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: 3483 /* no need to validate */ 3484 return VK_FALSE; 3485 break; 3486 default: 3487 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3488 DRAWSTATE_INVALID_UPDATE_STRUCT, "DS", 3489 "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", 3490 string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType); 3491 } 3492 if (VK_FALSE == skipCall) { 3493 // Set first stageFlags as reference and verify that all other updates match it 3494 VkShaderStageFlags refStageFlags = pLayout->stageFlags[startIndex]; 3495 for (i = startIndex; i <= endIndex; i++) { 3496 if (pLayout->descriptorTypes[i] != actualType) { 3497 skipCall |= log_msg( 3498 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3499 DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS", 3500 "Write descriptor update has descriptor type %s that does not match overlapping binding descriptor type of %s!", 3501 string_VkDescriptorType(actualType), string_VkDescriptorType(pLayout->descriptorTypes[i])); 3502 } 3503 if (pLayout->stageFlags[i] != refStageFlags) { 3504 skipCall |= log_msg( 3505 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3506 DRAWSTATE_DESCRIPTOR_STAGEFLAGS_MISMATCH, "DS", 3507 "Write descriptor update has stageFlags %x that do not match overlapping binding descriptor stageFlags of %x!", 3508 refStageFlags, pLayout->stageFlags[i]); 3509 } 3510 } 3511 } 3512 return skipCall; 3513} 3514 3515// Determine the update type, allocate a new struct of that type, shadow the given pUpdate 3516// struct into the pNewNode param. Return VK_TRUE if error condition encountered and callback signals early exit. 3517// NOTE : Calls to this function should be wrapped in mutex 3518static VkBool32 shadowUpdateNode(layer_data *my_data, const VkDevice device, GENERIC_HEADER *pUpdate, GENERIC_HEADER **pNewNode) { 3519 VkBool32 skipCall = VK_FALSE; 3520 VkWriteDescriptorSet *pWDS = NULL; 3521 VkCopyDescriptorSet *pCDS = NULL; 3522 switch (pUpdate->sType) { 3523 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 3524 pWDS = new VkWriteDescriptorSet; 3525 *pNewNode = (GENERIC_HEADER *)pWDS; 3526 memcpy(pWDS, pUpdate, sizeof(VkWriteDescriptorSet)); 3527 3528 switch (pWDS->descriptorType) { 3529 case VK_DESCRIPTOR_TYPE_SAMPLER: 3530 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: 3531 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: 3532 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { 3533 VkDescriptorImageInfo *info = new VkDescriptorImageInfo[pWDS->descriptorCount]; 3534 memcpy(info, pWDS->pImageInfo, pWDS->descriptorCount * sizeof(VkDescriptorImageInfo)); 3535 pWDS->pImageInfo = info; 3536 } break; 3537 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: 3538 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { 3539 VkBufferView *info = new VkBufferView[pWDS->descriptorCount]; 3540 memcpy(info, pWDS->pTexelBufferView, pWDS->descriptorCount * sizeof(VkBufferView)); 3541 pWDS->pTexelBufferView = info; 3542 } break; 3543 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: 3544 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: 3545 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: 3546 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { 3547 VkDescriptorBufferInfo *info = new VkDescriptorBufferInfo[pWDS->descriptorCount]; 3548 memcpy(info, pWDS->pBufferInfo, pWDS->descriptorCount * sizeof(VkDescriptorBufferInfo)); 3549 pWDS->pBufferInfo = info; 3550 } break; 3551 default: 3552 return VK_ERROR_VALIDATION_FAILED_EXT; 3553 break; 3554 } 3555 break; 3556 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: 3557 pCDS = new VkCopyDescriptorSet; 3558 *pNewNode = (GENERIC_HEADER *)pCDS; 3559 memcpy(pCDS, pUpdate, sizeof(VkCopyDescriptorSet)); 3560 break; 3561 default: 3562 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 3563 DRAWSTATE_INVALID_UPDATE_STRUCT, "DS", 3564 "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", 3565 string_VkStructureType(pUpdate->sType), pUpdate->sType)) 3566 return VK_TRUE; 3567 } 3568 // Make sure that pNext for the end of shadow copy is NULL 3569 (*pNewNode)->pNext = NULL; 3570 return skipCall; 3571} 3572 3573// Verify that given sampler is valid 3574static VkBool32 validateSampler(const layer_data *my_data, const VkSampler *pSampler, const VkBool32 immutable) { 3575 VkBool32 skipCall = VK_FALSE; 3576 auto sampIt = my_data->sampleMap.find(*pSampler); 3577 if (sampIt == my_data->sampleMap.end()) { 3578 if (!immutable) { 3579 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, 3580 (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS", 3581 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid sampler %#" PRIxLEAST64, 3582 (uint64_t)*pSampler); 3583 } else { // immutable 3584 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, 3585 (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS", 3586 "vkUpdateDescriptorSets: Attempt to update descriptor whose binding has an invalid immutable " 3587 "sampler %#" PRIxLEAST64, 3588 (uint64_t)*pSampler); 3589 } 3590 } else { 3591 // TODO : Any further checks we want to do on the sampler? 3592 } 3593 return skipCall; 3594} 3595 3596// find layout(s) on the cmd buf level 3597bool FindLayout(const GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, IMAGE_CMD_BUF_LAYOUT_NODE &node) { 3598 ImageSubresourcePair imgpair = {image, true, range}; 3599 auto imgsubIt = pCB->imageLayoutMap.find(imgpair); 3600 if (imgsubIt == pCB->imageLayoutMap.end()) { 3601 imgpair = {image, false, VkImageSubresource()}; 3602 imgsubIt = pCB->imageLayoutMap.find(imgpair); 3603 if (imgsubIt == pCB->imageLayoutMap.end()) 3604 return false; 3605 } 3606 node = imgsubIt->second; 3607 return true; 3608} 3609 3610// find layout(s) on the global level 3611bool FindLayout(const layer_data *my_data, ImageSubresourcePair imgpair, VkImageLayout &layout) { 3612 auto imgsubIt = my_data->imageLayoutMap.find(imgpair); 3613 if (imgsubIt == my_data->imageLayoutMap.end()) { 3614 imgpair = {imgpair.image, false, VkImageSubresource()}; 3615 imgsubIt = my_data->imageLayoutMap.find(imgpair); 3616 if (imgsubIt == my_data->imageLayoutMap.end()) 3617 return false; 3618 } 3619 layout = imgsubIt->second.layout; 3620 return true; 3621} 3622 3623bool FindLayout(const layer_data *my_data, VkImage image, VkImageSubresource range, VkImageLayout &layout) { 3624 ImageSubresourcePair imgpair = {image, true, range}; 3625 return FindLayout(my_data, imgpair, layout); 3626} 3627 3628bool FindLayouts(const layer_data *my_data, VkImage image, std::vector<VkImageLayout> &layouts) { 3629 auto sub_data = my_data->imageSubresourceMap.find(image); 3630 if (sub_data == my_data->imageSubresourceMap.end()) 3631 return false; 3632 auto imgIt = my_data->imageMap.find(image); 3633 if (imgIt == my_data->imageMap.end()) 3634 return false; 3635 bool ignoreGlobal = false; 3636 // TODO: Make this robust for >1 aspect mask. Now it will just say ignore 3637 // potential errors in this case. 3638 if (sub_data->second.size() >= (imgIt->second.createInfo.arrayLayers * imgIt->second.createInfo.mipLevels + 1)) { 3639 ignoreGlobal = true; 3640 } 3641 for (auto imgsubpair : sub_data->second) { 3642 if (ignoreGlobal && !imgsubpair.hasSubresource) 3643 continue; 3644 auto img_data = my_data->imageLayoutMap.find(imgsubpair); 3645 if (img_data != my_data->imageLayoutMap.end()) { 3646 layouts.push_back(img_data->second.layout); 3647 } 3648 } 3649 return true; 3650} 3651 3652// Set the layout on the global level 3653void SetLayout(layer_data *my_data, ImageSubresourcePair imgpair, const VkImageLayout &layout) { 3654 VkImage &image = imgpair.image; 3655 // TODO (mlentine): Maybe set format if new? Not used atm. 3656 my_data->imageLayoutMap[imgpair].layout = layout; 3657 // TODO (mlentine): Maybe make vector a set? 3658 auto subresource = std::find(my_data->imageSubresourceMap[image].begin(), my_data->imageSubresourceMap[image].end(), imgpair); 3659 if (subresource == my_data->imageSubresourceMap[image].end()) { 3660 my_data->imageSubresourceMap[image].push_back(imgpair); 3661 } 3662} 3663 3664void SetLayout(layer_data *my_data, VkImage image, const VkImageLayout &layout) { 3665 ImageSubresourcePair imgpair = {image, false, VkImageSubresource()}; 3666 SetLayout(my_data, imgpair, layout); 3667} 3668 3669void SetLayout(layer_data *my_data, VkImage image, VkImageSubresource range, const VkImageLayout &layout) { 3670 ImageSubresourcePair imgpair = {image, true, range}; 3671 SetLayout(my_data, imgpair, layout); 3672} 3673 3674// Set the layout on the cmdbuf level 3675void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node) { 3676 pCB->imageLayoutMap[imgpair] = node; 3677 // TODO (mlentine): Maybe make vector a set? 3678 auto subresource = std::find(pCB->imageSubresourceMap[image].begin(), pCB->imageSubresourceMap[image].end(), imgpair); 3679 if (subresource == pCB->imageSubresourceMap[image].end()) { 3680 pCB->imageSubresourceMap[image].push_back(imgpair); 3681 } 3682} 3683 3684void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, ImageSubresourcePair imgpair, const VkImageLayout &layout) { 3685 // TODO (mlentine): Maybe make vector a set? 3686 if (std::find(pCB->imageSubresourceMap[image].begin(), pCB->imageSubresourceMap[image].end(), imgpair) != 3687 pCB->imageSubresourceMap[image].end()) { 3688 pCB->imageLayoutMap[imgpair].layout = layout; 3689 } else { 3690 // TODO (mlentine): Could be expensive and might need to be removed. 3691 assert(imgpair.hasSubresource); 3692 IMAGE_CMD_BUF_LAYOUT_NODE node; 3693 FindLayout(pCB, image, imgpair.subresource, node); 3694 SetLayout(pCB, image, imgpair, {node.initialLayout, layout}); 3695 } 3696} 3697 3698void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, const IMAGE_CMD_BUF_LAYOUT_NODE &node) { 3699 ImageSubresourcePair imgpair = {image, false, VkImageSubresource()}; 3700 SetLayout(pCB, image, imgpair, node); 3701} 3702 3703void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, const IMAGE_CMD_BUF_LAYOUT_NODE &node) { 3704 ImageSubresourcePair imgpair = {image, true, range}; 3705 SetLayout(pCB, image, imgpair, node); 3706} 3707 3708void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, const VkImageLayout &layout) { 3709 ImageSubresourcePair imgpair = {image, false, VkImageSubresource()}; 3710 SetLayout(pCB, image, imgpair, layout); 3711} 3712 3713void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, const VkImageLayout &layout) { 3714 ImageSubresourcePair imgpair = {image, true, range}; 3715 SetLayout(pCB, image, imgpair, layout); 3716} 3717 3718void SetLayout(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkImageView imageView, const VkImageLayout &layout) { 3719 auto image_view_data = dev_data->imageViewMap.find(imageView); 3720 assert(image_view_data != dev_data->imageViewMap.end()); 3721 const VkImage &image = image_view_data->second.image; 3722 const VkImageSubresourceRange &subRange = image_view_data->second.subresourceRange; 3723 // TODO: Do not iterate over every possibility - consolidate where possible 3724 for (uint32_t j = 0; j < subRange.levelCount; j++) { 3725 uint32_t level = subRange.baseMipLevel + j; 3726 for (uint32_t k = 0; k < subRange.layerCount; k++) { 3727 uint32_t layer = subRange.baseArrayLayer + k; 3728 VkImageSubresource sub = {subRange.aspectMask, level, layer}; 3729 SetLayout(pCB, image, sub, layout); 3730 } 3731 } 3732} 3733 3734// Verify that given imageView is valid 3735static VkBool32 validateImageView(const layer_data *my_data, const VkImageView *pImageView, const VkImageLayout imageLayout) { 3736 VkBool32 skipCall = VK_FALSE; 3737 auto ivIt = my_data->imageViewMap.find(*pImageView); 3738 if (ivIt == my_data->imageViewMap.end()) { 3739 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3740 (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", 3741 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid imageView %#" PRIxLEAST64, 3742 (uint64_t)*pImageView); 3743 } else { 3744 // Validate that imageLayout is compatible with aspectMask and image format 3745 VkImageAspectFlags aspectMask = ivIt->second.subresourceRange.aspectMask; 3746 VkImage image = ivIt->second.image; 3747 // TODO : Check here in case we have a bad image 3748 VkFormat format = VK_FORMAT_MAX_ENUM; 3749 auto imgIt = my_data->imageMap.find(image); 3750 if (imgIt != my_data->imageMap.end()) { 3751 format = (*imgIt).second.createInfo.format; 3752 } else { 3753 // Also need to check the swapchains. 3754 auto swapchainIt = my_data->device_extensions.imageToSwapchainMap.find(image); 3755 if (swapchainIt != my_data->device_extensions.imageToSwapchainMap.end()) { 3756 VkSwapchainKHR swapchain = swapchainIt->second; 3757 auto swapchain_nodeIt = my_data->device_extensions.swapchainMap.find(swapchain); 3758 if (swapchain_nodeIt != my_data->device_extensions.swapchainMap.end()) { 3759 SWAPCHAIN_NODE *pswapchain_node = swapchain_nodeIt->second; 3760 format = pswapchain_node->createInfo.imageFormat; 3761 } 3762 } 3763 } 3764 if (format == VK_FORMAT_MAX_ENUM) { 3765 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 3766 (uint64_t)image, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", 3767 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid image %#" PRIxLEAST64 3768 " in imageView %#" PRIxLEAST64, 3769 (uint64_t)image, (uint64_t)*pImageView); 3770 } else { 3771 VkBool32 ds = vk_format_is_depth_or_stencil(format); 3772 switch (imageLayout) { 3773 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: 3774 // Only Color bit must be set 3775 if ((aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) { 3776 skipCall |= 3777 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3778 (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS", 3779 "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL " 3780 "and imageView %#" PRIxLEAST64 "" 3781 " that does not have VK_IMAGE_ASPECT_COLOR_BIT set.", 3782 (uint64_t)*pImageView); 3783 } 3784 // format must NOT be DS 3785 if (ds) { 3786 skipCall |= 3787 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3788 (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", 3789 "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL " 3790 "and imageView %#" PRIxLEAST64 "" 3791 " but the image format is %s which is not a color format.", 3792 (uint64_t)*pImageView, string_VkFormat(format)); 3793 } 3794 break; 3795 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: 3796 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: 3797 // Depth or stencil bit must be set, but both must NOT be set 3798 if (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) { 3799 if (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) { 3800 // both must NOT be set 3801 skipCall |= 3802 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3803 (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS", 3804 "vkUpdateDescriptorSets: Updating descriptor with imageView %#" PRIxLEAST64 "" 3805 " that has both STENCIL and DEPTH aspects set", 3806 (uint64_t)*pImageView); 3807 } 3808 } else if (!(aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) { 3809 // Neither were set 3810 skipCall |= 3811 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3812 (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS", 3813 "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 "" 3814 " that does not have STENCIL or DEPTH aspect set.", 3815 string_VkImageLayout(imageLayout), (uint64_t)*pImageView); 3816 } 3817 // format must be DS 3818 if (!ds) { 3819 skipCall |= 3820 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, 3821 (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", 3822 "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 "" 3823 " but the image format is %s which is not a depth/stencil format.", 3824 string_VkImageLayout(imageLayout), (uint64_t)*pImageView, string_VkFormat(format)); 3825 } 3826 break; 3827 default: 3828 // anything to check for other layouts? 3829 break; 3830 } 3831 } 3832 } 3833 return skipCall; 3834} 3835 3836// Verify that given bufferView is valid 3837static VkBool32 validateBufferView(const layer_data *my_data, const VkBufferView *pBufferView) { 3838 VkBool32 skipCall = VK_FALSE; 3839 auto sampIt = my_data->bufferViewMap.find(*pBufferView); 3840 if (sampIt == my_data->bufferViewMap.end()) { 3841 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT, 3842 (uint64_t)*pBufferView, __LINE__, DRAWSTATE_BUFFERVIEW_DESCRIPTOR_ERROR, "DS", 3843 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid bufferView %#" PRIxLEAST64, 3844 (uint64_t)*pBufferView); 3845 } else { 3846 // TODO : Any further checks we want to do on the bufferView? 3847 } 3848 return skipCall; 3849} 3850 3851// Verify that given bufferInfo is valid 3852static VkBool32 validateBufferInfo(const layer_data *my_data, const VkDescriptorBufferInfo *pBufferInfo) { 3853 VkBool32 skipCall = VK_FALSE; 3854 auto sampIt = my_data->bufferMap.find(pBufferInfo->buffer); 3855 if (sampIt == my_data->bufferMap.end()) { 3856 skipCall |= 3857 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, 3858 (uint64_t)pBufferInfo->buffer, __LINE__, DRAWSTATE_BUFFERINFO_DESCRIPTOR_ERROR, "DS", 3859 "vkUpdateDescriptorSets: Attempt to update descriptor where bufferInfo has invalid buffer %#" PRIxLEAST64, 3860 (uint64_t)pBufferInfo->buffer); 3861 } else { 3862 // TODO : Any further checks we want to do on the bufferView? 3863 } 3864 return skipCall; 3865} 3866 3867static VkBool32 validateUpdateContents(const layer_data *my_data, const VkWriteDescriptorSet *pWDS, 3868 const VkDescriptorSetLayoutBinding *pLayoutBinding) { 3869 VkBool32 skipCall = VK_FALSE; 3870 // First verify that for the given Descriptor type, the correct DescriptorInfo data is supplied 3871 const VkSampler *pSampler = NULL; 3872 VkBool32 immutable = VK_FALSE; 3873 uint32_t i = 0; 3874 // For given update type, verify that update contents are correct 3875 switch (pWDS->descriptorType) { 3876 case VK_DESCRIPTOR_TYPE_SAMPLER: 3877 for (i = 0; i < pWDS->descriptorCount; ++i) { 3878 skipCall |= validateSampler(my_data, &(pWDS->pImageInfo[i].sampler), immutable); 3879 } 3880 break; 3881 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: 3882 for (i = 0; i < pWDS->descriptorCount; ++i) { 3883 if (NULL == pLayoutBinding->pImmutableSamplers) { 3884 pSampler = &(pWDS->pImageInfo[i].sampler); 3885 if (immutable) { 3886 skipCall |= log_msg( 3887 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, 3888 (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS", 3889 "vkUpdateDescriptorSets: Update #%u is not an immutable sampler %#" PRIxLEAST64 3890 ", but previous update(s) from this " 3891 "VkWriteDescriptorSet struct used an immutable sampler. All updates from a single struct must either " 3892 "use immutable or non-immutable samplers.", 3893 i, (uint64_t)*pSampler); 3894 } 3895 } else { 3896 if (i > 0 && !immutable) { 3897 skipCall |= log_msg( 3898 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, 3899 (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS", 3900 "vkUpdateDescriptorSets: Update #%u is an immutable sampler, but previous update(s) from this " 3901 "VkWriteDescriptorSet struct used a non-immutable sampler. All updates from a single struct must either " 3902 "use immutable or non-immutable samplers.", 3903 i); 3904 } 3905 immutable = VK_TRUE; 3906 pSampler = &(pLayoutBinding->pImmutableSamplers[i]); 3907 } 3908 skipCall |= validateSampler(my_data, pSampler, immutable); 3909 } 3910 // Intentionally fall through here to also validate image stuff 3911 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: 3912 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: 3913 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: 3914 for (i = 0; i < pWDS->descriptorCount; ++i) { 3915 skipCall |= validateImageView(my_data, &(pWDS->pImageInfo[i].imageView), pWDS->pImageInfo[i].imageLayout); 3916 } 3917 break; 3918 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: 3919 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: 3920 for (i = 0; i < pWDS->descriptorCount; ++i) { 3921 skipCall |= validateBufferView(my_data, &(pWDS->pTexelBufferView[i])); 3922 } 3923 break; 3924 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: 3925 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: 3926 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: 3927 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: 3928 for (i = 0; i < pWDS->descriptorCount; ++i) { 3929 skipCall |= validateBufferInfo(my_data, &(pWDS->pBufferInfo[i])); 3930 } 3931 break; 3932 default: 3933 break; 3934 } 3935 return skipCall; 3936} 3937// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer 3938// func_str is the name of the calling function 3939// Return VK_FALSE if no errors occur 3940// Return VK_TRUE if validation error occurs and callback returns VK_TRUE (to skip upcoming API call down the chain) 3941VkBool32 validateIdleDescriptorSet(const layer_data *my_data, VkDescriptorSet set, std::string func_str) { 3942 VkBool32 skip_call = VK_FALSE; 3943 auto set_node = my_data->setMap.find(set); 3944 if (set_node == my_data->setMap.end()) { 3945 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 3946 (uint64_t)(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS", 3947 "Cannot call %s() on descriptor set %" PRIxLEAST64 " that has not been allocated.", func_str.c_str(), 3948 (uint64_t)(set)); 3949 } else { 3950 if (set_node->second->in_use.load()) { 3951 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 3952 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)(set), __LINE__, DRAWSTATE_OBJECT_INUSE, 3953 "DS", "Cannot call %s() on descriptor set %" PRIxLEAST64 " that is in use by a command buffer.", 3954 func_str.c_str(), (uint64_t)(set)); 3955 } 3956 } 3957 return skip_call; 3958} 3959static void invalidateBoundCmdBuffers(layer_data *dev_data, const SET_NODE *pSet) { 3960 // Flag any CBs this set is bound to as INVALID 3961 for (auto cb : pSet->boundCmdBuffers) { 3962 auto cb_node = dev_data->commandBufferMap.find(cb); 3963 if (cb_node != dev_data->commandBufferMap.end()) { 3964 cb_node->second->state = CB_INVALID; 3965 } 3966 } 3967} 3968// update DS mappings based on write and copy update arrays 3969static VkBool32 dsUpdate(layer_data *my_data, VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pWDS, 3970 uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pCDS) { 3971 VkBool32 skipCall = VK_FALSE; 3972 3973 LAYOUT_NODE *pLayout = NULL; 3974 VkDescriptorSetLayoutCreateInfo *pLayoutCI = NULL; 3975 // Validate Write updates 3976 uint32_t i = 0; 3977 for (i = 0; i < descriptorWriteCount; i++) { 3978 VkDescriptorSet ds = pWDS[i].dstSet; 3979 SET_NODE *pSet = my_data->setMap[ds]; 3980 // Set being updated cannot be in-flight 3981 if ((skipCall = validateIdleDescriptorSet(my_data, ds, "VkUpdateDescriptorSets")) == VK_TRUE) 3982 return skipCall; 3983 // If set is bound to any cmdBuffers, mark them invalid 3984 invalidateBoundCmdBuffers(my_data, pSet); 3985 GENERIC_HEADER *pUpdate = (GENERIC_HEADER *)&pWDS[i]; 3986 pLayout = pSet->pLayout; 3987 // First verify valid update struct 3988 if ((skipCall = validUpdateStruct(my_data, device, pUpdate)) == VK_TRUE) { 3989 break; 3990 } 3991 uint32_t binding = 0, endIndex = 0; 3992 binding = pWDS[i].dstBinding; 3993 auto bindingToIndex = pLayout->bindingToIndexMap.find(binding); 3994 // Make sure that layout being updated has the binding being updated 3995 if (bindingToIndex == pLayout->bindingToIndexMap.end()) { 3996 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 3997 (uint64_t)(ds), __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS", 3998 "Descriptor Set %" PRIu64 " does not have binding to match " 3999 "update binding %u for update type " 4000 "%s!", 4001 (uint64_t)(ds), binding, string_VkStructureType(pUpdate->sType)); 4002 } else { 4003 // Next verify that update falls within size of given binding 4004 endIndex = getUpdateEndIndex(my_data, device, pLayout, binding, pWDS[i].dstArrayElement, pUpdate); 4005 if (getBindingEndIndex(pLayout, binding) < endIndex) { 4006 pLayoutCI = &pLayout->createInfo; 4007 string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS} "); 4008 skipCall |= 4009 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4010 (uint64_t)(ds), __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS", 4011 "Descriptor update type of %s is out of bounds for matching binding %u in Layout w/ CI:\n%s!", 4012 string_VkStructureType(pUpdate->sType), binding, DSstr.c_str()); 4013 } else { // TODO : should we skip update on a type mismatch or force it? 4014 uint32_t startIndex; 4015 startIndex = getUpdateStartIndex(my_data, device, pLayout, binding, pWDS[i].dstArrayElement, pUpdate); 4016 // Layout bindings match w/ update, now verify that update type 4017 // & stageFlags are the same for entire update 4018 if ((skipCall = validateUpdateConsistency(my_data, device, pLayout, pUpdate, startIndex, endIndex)) == VK_FALSE) { 4019 // The update is within bounds and consistent, but need to 4020 // make sure contents make sense as well 4021 if ((skipCall = validateUpdateContents(my_data, &pWDS[i], 4022 &pLayout->createInfo.pBindings[bindingToIndex->second])) == VK_FALSE) { 4023 // Update is good. Save the update info 4024 // Create new update struct for this set's shadow copy 4025 GENERIC_HEADER *pNewNode = NULL; 4026 skipCall |= shadowUpdateNode(my_data, device, pUpdate, &pNewNode); 4027 if (NULL == pNewNode) { 4028 skipCall |= log_msg( 4029 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4030 (uint64_t)(ds), __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", 4031 "Out of memory while attempting to allocate UPDATE struct in vkUpdateDescriptors()"); 4032 } else { 4033 // Insert shadow node into LL of updates for this set 4034 pNewNode->pNext = pSet->pUpdateStructs; 4035 pSet->pUpdateStructs = pNewNode; 4036 // Now update appropriate descriptor(s) to point to new Update node 4037 for (uint32_t j = startIndex; j <= endIndex; j++) { 4038 assert(j < pSet->descriptorCount); 4039 pSet->ppDescriptors[j] = pNewNode; 4040 } 4041 } 4042 } 4043 } 4044 } 4045 } 4046 } 4047 // Now validate copy updates 4048 for (i = 0; i < descriptorCopyCount; ++i) { 4049 SET_NODE *pSrcSet = NULL, *pDstSet = NULL; 4050 LAYOUT_NODE *pSrcLayout = NULL, *pDstLayout = NULL; 4051 uint32_t srcStartIndex = 0, srcEndIndex = 0, dstStartIndex = 0, dstEndIndex = 0; 4052 // For each copy make sure that update falls within given layout and that types match 4053 pSrcSet = my_data->setMap[pCDS[i].srcSet]; 4054 pDstSet = my_data->setMap[pCDS[i].dstSet]; 4055 // Set being updated cannot be in-flight 4056 if ((skipCall = validateIdleDescriptorSet(my_data, pDstSet->set, "VkUpdateDescriptorSets")) == VK_TRUE) 4057 return skipCall; 4058 invalidateBoundCmdBuffers(my_data, pDstSet); 4059 pSrcLayout = pSrcSet->pLayout; 4060 pDstLayout = pDstSet->pLayout; 4061 // Validate that src binding is valid for src set layout 4062 if (pSrcLayout->bindingToIndexMap.find(pCDS[i].srcBinding) == pSrcLayout->bindingToIndexMap.end()) { 4063 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4064 (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS", 4065 "Copy descriptor update %u has srcBinding %u " 4066 "which is out of bounds for underlying SetLayout " 4067 "%#" PRIxLEAST64 " which only has bindings 0-%u.", 4068 i, pCDS[i].srcBinding, (uint64_t)pSrcLayout->layout, pSrcLayout->createInfo.bindingCount - 1); 4069 } else if (pDstLayout->bindingToIndexMap.find(pCDS[i].dstBinding) == pDstLayout->bindingToIndexMap.end()) { 4070 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4071 (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS", 4072 "Copy descriptor update %u has dstBinding %u " 4073 "which is out of bounds for underlying SetLayout " 4074 "%#" PRIxLEAST64 " which only has bindings 0-%u.", 4075 i, pCDS[i].dstBinding, (uint64_t)pDstLayout->layout, pDstLayout->createInfo.bindingCount - 1); 4076 } else { 4077 // Proceed with validation. Bindings are ok, but make sure update is within bounds of given layout 4078 srcEndIndex = getUpdateEndIndex(my_data, device, pSrcLayout, pCDS[i].srcBinding, pCDS[i].srcArrayElement, 4079 (const GENERIC_HEADER *)&(pCDS[i])); 4080 dstEndIndex = getUpdateEndIndex(my_data, device, pDstLayout, pCDS[i].dstBinding, pCDS[i].dstArrayElement, 4081 (const GENERIC_HEADER *)&(pCDS[i])); 4082 if (getBindingEndIndex(pSrcLayout, pCDS[i].srcBinding) < srcEndIndex) { 4083 pLayoutCI = &pSrcLayout->createInfo; 4084 string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS} "); 4085 skipCall |= 4086 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4087 (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS", 4088 "Copy descriptor src update is out of bounds for matching binding %u in Layout w/ CI:\n%s!", 4089 pCDS[i].srcBinding, DSstr.c_str()); 4090 } else if (getBindingEndIndex(pDstLayout, pCDS[i].dstBinding) < dstEndIndex) { 4091 pLayoutCI = &pDstLayout->createInfo; 4092 string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS} "); 4093 skipCall |= 4094 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4095 (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS", 4096 "Copy descriptor dest update is out of bounds for matching binding %u in Layout w/ CI:\n%s!", 4097 pCDS[i].dstBinding, DSstr.c_str()); 4098 } else { 4099 srcStartIndex = getUpdateStartIndex(my_data, device, pSrcLayout, pCDS[i].srcBinding, pCDS[i].srcArrayElement, 4100 (const GENERIC_HEADER *)&(pCDS[i])); 4101 dstStartIndex = getUpdateStartIndex(my_data, device, pDstLayout, pCDS[i].dstBinding, pCDS[i].dstArrayElement, 4102 (const GENERIC_HEADER *)&(pCDS[i])); 4103 for (uint32_t j = 0; j < pCDS[i].descriptorCount; ++j) { 4104 // For copy just make sure that the types match and then perform the update 4105 if (pSrcLayout->descriptorTypes[srcStartIndex + j] != pDstLayout->descriptorTypes[dstStartIndex + j]) { 4106 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 4107 __LINE__, DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS", 4108 "Copy descriptor update index %u, update count #%u, has src update descriptor type %s " 4109 "that does not match overlapping dest descriptor type of %s!", 4110 i, j + 1, string_VkDescriptorType(pSrcLayout->descriptorTypes[srcStartIndex + j]), 4111 string_VkDescriptorType(pDstLayout->descriptorTypes[dstStartIndex + j])); 4112 } else { 4113 // point dst descriptor at corresponding src descriptor 4114 // TODO : This may be a hole. I believe copy should be its own copy, 4115 // otherwise a subsequent write update to src will incorrectly affect the copy 4116 pDstSet->ppDescriptors[j + dstStartIndex] = pSrcSet->ppDescriptors[j + srcStartIndex]; 4117 pDstSet->pUpdateStructs = pSrcSet->pUpdateStructs; 4118 } 4119 } 4120 } 4121 } 4122 } 4123 return skipCall; 4124} 4125 4126// Verify that given pool has descriptors that are being requested for allocation 4127static VkBool32 validate_descriptor_availability_in_pool(layer_data *dev_data, DESCRIPTOR_POOL_NODE *pPoolNode, uint32_t count, 4128 const VkDescriptorSetLayout *pSetLayouts) { 4129 VkBool32 skipCall = VK_FALSE; 4130 uint32_t i = 0, j = 0; 4131 for (i = 0; i < count; ++i) { 4132 LAYOUT_NODE *pLayout = getLayoutNode(dev_data, pSetLayouts[i]); 4133 if (NULL == pLayout) { 4134 skipCall |= 4135 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, 4136 (uint64_t)pSetLayouts[i], __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS", 4137 "Unable to find set layout node for layout %#" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call", 4138 (uint64_t)pSetLayouts[i]); 4139 } else { 4140 uint32_t typeIndex = 0, poolSizeCount = 0; 4141 for (j = 0; j < pLayout->createInfo.bindingCount; ++j) { 4142 typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBindings[j].descriptorType); 4143 poolSizeCount = pLayout->createInfo.pBindings[j].descriptorCount; 4144 if (poolSizeCount > pPoolNode->availableDescriptorTypeCount[typeIndex]) { 4145 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 4146 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pLayout->layout, __LINE__, 4147 DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS", 4148 "Unable to allocate %u descriptors of type %s from pool %#" PRIxLEAST64 4149 ". This pool only has %u descriptors of this type remaining.", 4150 poolSizeCount, string_VkDescriptorType(pLayout->createInfo.pBindings[j].descriptorType), 4151 (uint64_t)pPoolNode->pool, pPoolNode->availableDescriptorTypeCount[typeIndex]); 4152 } else { // Decrement available descriptors of this type 4153 pPoolNode->availableDescriptorTypeCount[typeIndex] -= poolSizeCount; 4154 } 4155 } 4156 } 4157 } 4158 return skipCall; 4159} 4160 4161// Free the shadowed update node for this Set 4162// NOTE : Calls to this function should be wrapped in mutex 4163static void freeShadowUpdateTree(SET_NODE *pSet) { 4164 GENERIC_HEADER *pShadowUpdate = pSet->pUpdateStructs; 4165 pSet->pUpdateStructs = NULL; 4166 GENERIC_HEADER *pFreeUpdate = pShadowUpdate; 4167 // Clear the descriptor mappings as they will now be invalid 4168 memset(pSet->ppDescriptors, 0, pSet->descriptorCount * sizeof(GENERIC_HEADER *)); 4169 while (pShadowUpdate) { 4170 pFreeUpdate = pShadowUpdate; 4171 pShadowUpdate = (GENERIC_HEADER *)pShadowUpdate->pNext; 4172 VkWriteDescriptorSet *pWDS = NULL; 4173 switch (pFreeUpdate->sType) { 4174 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: 4175 pWDS = (VkWriteDescriptorSet *)pFreeUpdate; 4176 switch (pWDS->descriptorType) { 4177 case VK_DESCRIPTOR_TYPE_SAMPLER: 4178 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: 4179 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: 4180 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { 4181 delete[] pWDS->pImageInfo; 4182 } break; 4183 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: 4184 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { 4185 delete[] pWDS->pTexelBufferView; 4186 } break; 4187 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: 4188 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: 4189 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: 4190 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { 4191 delete[] pWDS->pBufferInfo; 4192 } break; 4193 default: 4194 break; 4195 } 4196 break; 4197 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: 4198 break; 4199 default: 4200 assert(0); 4201 break; 4202 } 4203 delete pFreeUpdate; 4204 } 4205} 4206 4207// Free all DS Pools including their Sets & related sub-structs 4208// NOTE : Calls to this function should be wrapped in mutex 4209static void deletePools(layer_data *my_data) { 4210 if (my_data->descriptorPoolMap.size() <= 0) 4211 return; 4212 for (auto ii = my_data->descriptorPoolMap.begin(); ii != my_data->descriptorPoolMap.end(); ++ii) { 4213 SET_NODE *pSet = (*ii).second->pSets; 4214 SET_NODE *pFreeSet = pSet; 4215 while (pSet) { 4216 pFreeSet = pSet; 4217 pSet = pSet->pNext; 4218 // Freeing layouts handled in deleteLayouts() function 4219 // Free Update shadow struct tree 4220 freeShadowUpdateTree(pFreeSet); 4221 delete[] pFreeSet->ppDescriptors; 4222 delete pFreeSet; 4223 } 4224 delete (*ii).second; 4225 } 4226 my_data->descriptorPoolMap.clear(); 4227} 4228 4229// WARN : Once deleteLayouts() called, any layout ptrs in Pool/Set data structure will be invalid 4230// NOTE : Calls to this function should be wrapped in mutex 4231static void deleteLayouts(layer_data *my_data) { 4232 if (my_data->descriptorSetLayoutMap.size() <= 0) 4233 return; 4234 for (auto ii = my_data->descriptorSetLayoutMap.begin(); ii != my_data->descriptorSetLayoutMap.end(); ++ii) { 4235 LAYOUT_NODE *pLayout = (*ii).second; 4236 if (pLayout->createInfo.pBindings) { 4237 for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) { 4238 delete[] pLayout->createInfo.pBindings[i].pImmutableSamplers; 4239 } 4240 delete[] pLayout->createInfo.pBindings; 4241 } 4242 delete pLayout; 4243 } 4244 my_data->descriptorSetLayoutMap.clear(); 4245} 4246 4247// Currently clearing a set is removing all previous updates to that set 4248// TODO : Validate if this is correct clearing behavior 4249static void clearDescriptorSet(layer_data *my_data, VkDescriptorSet set) { 4250 SET_NODE *pSet = getSetNode(my_data, set); 4251 if (!pSet) { 4252 // TODO : Return error 4253 } else { 4254 freeShadowUpdateTree(pSet); 4255 } 4256} 4257 4258static void clearDescriptorPool(layer_data *my_data, const VkDevice device, const VkDescriptorPool pool, 4259 VkDescriptorPoolResetFlags flags) { 4260 DESCRIPTOR_POOL_NODE *pPool = getPoolNode(my_data, pool); 4261 if (!pPool) { 4262 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, 4263 (uint64_t)pool, __LINE__, DRAWSTATE_INVALID_POOL, "DS", 4264 "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkResetDescriptorPool() call", (uint64_t)pool); 4265 } else { 4266 // TODO: validate flags 4267 // For every set off of this pool, clear it 4268 SET_NODE *pSet = pPool->pSets; 4269 while (pSet) { 4270 clearDescriptorSet(my_data, pSet->set); 4271 pSet = pSet->pNext; 4272 } 4273 // Reset available count to max count for this pool 4274 for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) { 4275 pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i]; 4276 } 4277 } 4278} 4279 4280// For given CB object, fetch associated CB Node from map 4281static GLOBAL_CB_NODE *getCBNode(layer_data *my_data, const VkCommandBuffer cb) { 4282 if (my_data->commandBufferMap.count(cb) == 0) { 4283 // TODO : How to pass cb as srcObj here? 4284 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, 4285 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", "Attempt to use CommandBuffer %#" PRIxLEAST64 " that doesn't exist!", 4286 (uint64_t)(cb)); 4287 return NULL; 4288 } 4289 return my_data->commandBufferMap[cb]; 4290} 4291 4292// Free all CB Nodes 4293// NOTE : Calls to this function should be wrapped in mutex 4294static void deleteCommandBuffers(layer_data *my_data) { 4295 if (my_data->commandBufferMap.size() <= 0) { 4296 return; 4297 } 4298 for (auto ii = my_data->commandBufferMap.begin(); ii != my_data->commandBufferMap.end(); ++ii) { 4299 delete (*ii).second; 4300 } 4301 my_data->commandBufferMap.clear(); 4302} 4303 4304static VkBool32 report_error_no_cb_begin(const layer_data *dev_data, const VkCommandBuffer cb, const char *caller_name) { 4305 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 4306 (uint64_t)cb, __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS", 4307 "You must call vkBeginCommandBuffer() before this call to %s", caller_name); 4308} 4309 4310VkBool32 validateCmdsInCmdBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) { 4311 if (!pCB->activeRenderPass) 4312 return VK_FALSE; 4313 VkBool32 skip_call = VK_FALSE; 4314 if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS && cmd_type != CMD_EXECUTECOMMANDS) { 4315 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4316 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 4317 "Commands cannot be called in a subpass using secondary command buffers."); 4318 } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) { 4319 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4320 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 4321 "vkCmdExecuteCommands() cannot be called in a subpass using inline commands."); 4322 } 4323 return skip_call; 4324} 4325 4326static bool checkGraphicsBit(const layer_data *my_data, VkQueueFlags flags, const char *name) { 4327 if (!(flags & VK_QUEUE_GRAPHICS_BIT)) 4328 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4329 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 4330 "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name); 4331 return false; 4332} 4333 4334static bool checkComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) { 4335 if (!(flags & VK_QUEUE_COMPUTE_BIT)) 4336 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4337 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 4338 "Cannot call %s on a command buffer allocated from a pool without compute capabilities.", name); 4339 return false; 4340} 4341 4342static bool checkGraphicsOrComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) { 4343 if (!((flags & VK_QUEUE_GRAPHICS_BIT) || (flags & VK_QUEUE_COMPUTE_BIT))) 4344 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4345 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 4346 "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name); 4347 return false; 4348} 4349 4350// Add specified CMD to the CmdBuffer in given pCB, flagging errors if CB is not 4351// in the recording state or if there's an issue with the Cmd ordering 4352static VkBool32 addCmd(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name) { 4353 VkBool32 skipCall = VK_FALSE; 4354 auto pool_data = my_data->commandPoolMap.find(pCB->createInfo.commandPool); 4355 if (pool_data != my_data->commandPoolMap.end()) { 4356 VkQueueFlags flags = my_data->physDevProperties.queue_family_properties[pool_data->second.queueFamilyIndex].queueFlags; 4357 switch (cmd) { 4358 case CMD_BINDPIPELINE: 4359 case CMD_BINDPIPELINEDELTA: 4360 case CMD_BINDDESCRIPTORSETS: 4361 case CMD_FILLBUFFER: 4362 case CMD_CLEARCOLORIMAGE: 4363 case CMD_SETEVENT: 4364 case CMD_RESETEVENT: 4365 case CMD_WAITEVENTS: 4366 case CMD_BEGINQUERY: 4367 case CMD_ENDQUERY: 4368 case CMD_RESETQUERYPOOL: 4369 case CMD_COPYQUERYPOOLRESULTS: 4370 case CMD_WRITETIMESTAMP: 4371 skipCall |= checkGraphicsOrComputeBit(my_data, flags, cmdTypeToString(cmd).c_str()); 4372 break; 4373 case CMD_SETVIEWPORTSTATE: 4374 case CMD_SETSCISSORSTATE: 4375 case CMD_SETLINEWIDTHSTATE: 4376 case CMD_SETDEPTHBIASSTATE: 4377 case CMD_SETBLENDSTATE: 4378 case CMD_SETDEPTHBOUNDSSTATE: 4379 case CMD_SETSTENCILREADMASKSTATE: 4380 case CMD_SETSTENCILWRITEMASKSTATE: 4381 case CMD_SETSTENCILREFERENCESTATE: 4382 case CMD_BINDINDEXBUFFER: 4383 case CMD_BINDVERTEXBUFFER: 4384 case CMD_DRAW: 4385 case CMD_DRAWINDEXED: 4386 case CMD_DRAWINDIRECT: 4387 case CMD_DRAWINDEXEDINDIRECT: 4388 case CMD_BLITIMAGE: 4389 case CMD_CLEARATTACHMENTS: 4390 case CMD_CLEARDEPTHSTENCILIMAGE: 4391 case CMD_RESOLVEIMAGE: 4392 case CMD_BEGINRENDERPASS: 4393 case CMD_NEXTSUBPASS: 4394 case CMD_ENDRENDERPASS: 4395 skipCall |= checkGraphicsBit(my_data, flags, cmdTypeToString(cmd).c_str()); 4396 break; 4397 case CMD_DISPATCH: 4398 case CMD_DISPATCHINDIRECT: 4399 skipCall |= checkComputeBit(my_data, flags, cmdTypeToString(cmd).c_str()); 4400 break; 4401 case CMD_COPYBUFFER: 4402 case CMD_COPYIMAGE: 4403 case CMD_COPYBUFFERTOIMAGE: 4404 case CMD_COPYIMAGETOBUFFER: 4405 case CMD_CLONEIMAGEDATA: 4406 case CMD_UPDATEBUFFER: 4407 case CMD_PIPELINEBARRIER: 4408 case CMD_EXECUTECOMMANDS: 4409 break; 4410 default: 4411 break; 4412 } 4413 } 4414 if (pCB->state != CB_RECORDING) { 4415 skipCall |= report_error_no_cb_begin(my_data, pCB->commandBuffer, caller_name); 4416 skipCall |= validateCmdsInCmdBuffer(my_data, pCB, cmd); 4417 CMD_NODE cmdNode = {}; 4418 // init cmd node and append to end of cmd LL 4419 cmdNode.cmdNumber = ++pCB->numCmds; 4420 cmdNode.type = cmd; 4421 pCB->cmds.push_back(cmdNode); 4422 } 4423 return skipCall; 4424} 4425// Reset the command buffer state 4426// Maintain the createInfo and set state to CB_NEW, but clear all other state 4427static void resetCB(layer_data *my_data, const VkCommandBuffer cb) { 4428 GLOBAL_CB_NODE *pCB = my_data->commandBufferMap[cb]; 4429 if (pCB) { 4430 pCB->cmds.clear(); 4431 // Reset CB state (note that createInfo is not cleared) 4432 pCB->commandBuffer = cb; 4433 memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo)); 4434 memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo)); 4435 pCB->fence = 0; 4436 pCB->numCmds = 0; 4437 memset(pCB->drawCount, 0, NUM_DRAW_TYPES * sizeof(uint64_t)); 4438 pCB->state = CB_NEW; 4439 pCB->submitCount = 0; 4440 pCB->status = 0; 4441 pCB->lastBoundPipeline = 0; 4442 pCB->lastVtxBinding = 0; 4443 pCB->boundVtxBuffers.clear(); 4444 pCB->viewports.clear(); 4445 pCB->scissors.clear(); 4446 pCB->lineWidth = 0; 4447 pCB->depthBiasConstantFactor = 0; 4448 pCB->depthBiasClamp = 0; 4449 pCB->depthBiasSlopeFactor = 0; 4450 memset(pCB->blendConstants, 0, 4 * sizeof(float)); 4451 pCB->minDepthBounds = 0; 4452 pCB->maxDepthBounds = 0; 4453 memset(&pCB->front, 0, sizeof(stencil_data)); 4454 memset(&pCB->back, 0, sizeof(stencil_data)); 4455 pCB->lastBoundDescriptorSet = 0; 4456 pCB->lastBoundPipelineLayout = 0; 4457 memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo)); 4458 pCB->activeRenderPass = 0; 4459 pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE; 4460 pCB->activeSubpass = 0; 4461 pCB->framebuffer = 0; 4462 // Before clearing uniqueBoundSets, remove this CB off of its boundCBs 4463 for (auto set : pCB->uniqueBoundSets) { 4464 auto set_node = my_data->setMap.find(set); 4465 if (set_node != my_data->setMap.end()) { 4466 set_node->second->boundCmdBuffers.erase(pCB->commandBuffer); 4467 } 4468 } 4469 pCB->uniqueBoundSets.clear(); 4470 pCB->destroyedSets.clear(); 4471 pCB->updatedSets.clear(); 4472 pCB->destroyedFramebuffers.clear(); 4473 pCB->boundDescriptorSets.clear(); 4474 pCB->waitedEvents.clear(); 4475 pCB->semaphores.clear(); 4476 pCB->events.clear(); 4477 pCB->waitedEventsBeforeQueryReset.clear(); 4478 pCB->queryToStateMap.clear(); 4479 pCB->activeQueries.clear(); 4480 pCB->startedQueries.clear(); 4481 pCB->imageLayoutMap.clear(); 4482 pCB->eventToStageMap.clear(); 4483 pCB->drawData.clear(); 4484 pCB->currentDrawData.buffers.clear(); 4485 pCB->primaryCommandBuffer = VK_NULL_HANDLE; 4486 pCB->secondaryCommandBuffers.clear(); 4487 pCB->dynamicOffsets.clear(); 4488 } 4489} 4490 4491// Set PSO-related status bits for CB, including dynamic state set via PSO 4492static void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_NODE *pPipe) { 4493 for (uint32_t i = 0; i < pPipe->cbStateCI.attachmentCount; i++) { 4494 if (0 != pPipe->pAttachments[i].colorWriteMask) { 4495 pCB->status |= CBSTATUS_COLOR_BLEND_WRITE_ENABLE; 4496 } 4497 } 4498 if (pPipe->dsStateCI.depthWriteEnable) { 4499 pCB->status |= CBSTATUS_DEPTH_WRITE_ENABLE; 4500 } 4501 if (pPipe->dsStateCI.stencilTestEnable) { 4502 pCB->status |= CBSTATUS_STENCIL_TEST_ENABLE; 4503 } 4504 // Account for any dynamic state not set via this PSO 4505 if (!pPipe->dynStateCI.dynamicStateCount) { // All state is static 4506 pCB->status = CBSTATUS_ALL; 4507 } else { 4508 // First consider all state on 4509 // Then unset any state that's noted as dynamic in PSO 4510 // Finally OR that into CB statemask 4511 CBStatusFlags psoDynStateMask = CBSTATUS_ALL; 4512 for (uint32_t i = 0; i < pPipe->dynStateCI.dynamicStateCount; i++) { 4513 switch (pPipe->dynStateCI.pDynamicStates[i]) { 4514 case VK_DYNAMIC_STATE_VIEWPORT: 4515 psoDynStateMask &= ~CBSTATUS_VIEWPORT_SET; 4516 break; 4517 case VK_DYNAMIC_STATE_SCISSOR: 4518 psoDynStateMask &= ~CBSTATUS_SCISSOR_SET; 4519 break; 4520 case VK_DYNAMIC_STATE_LINE_WIDTH: 4521 psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET; 4522 break; 4523 case VK_DYNAMIC_STATE_DEPTH_BIAS: 4524 psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET; 4525 break; 4526 case VK_DYNAMIC_STATE_BLEND_CONSTANTS: 4527 psoDynStateMask &= ~CBSTATUS_BLEND_SET; 4528 break; 4529 case VK_DYNAMIC_STATE_DEPTH_BOUNDS: 4530 psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET; 4531 break; 4532 case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK: 4533 psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET; 4534 break; 4535 case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK: 4536 psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET; 4537 break; 4538 case VK_DYNAMIC_STATE_STENCIL_REFERENCE: 4539 psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET; 4540 break; 4541 default: 4542 // TODO : Flag error here 4543 break; 4544 } 4545 } 4546 pCB->status |= psoDynStateMask; 4547 } 4548} 4549 4550// Print the last bound Gfx Pipeline 4551static VkBool32 printPipeline(layer_data *my_data, const VkCommandBuffer cb) { 4552 VkBool32 skipCall = VK_FALSE; 4553 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb); 4554 if (pCB) { 4555 PIPELINE_NODE *pPipeTrav = getPipeline(my_data, pCB->lastBoundPipeline); 4556 if (!pPipeTrav) { 4557 // nothing to print 4558 } else { 4559 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 4560 __LINE__, DRAWSTATE_NONE, "DS", "%s", 4561 vk_print_vkgraphicspipelinecreateinfo(&pPipeTrav->graphicsPipelineCI, "{DS}").c_str()); 4562 } 4563 } 4564 return skipCall; 4565} 4566 4567// Print details of DS config to stdout 4568static VkBool32 printDSConfig(layer_data *my_data, const VkCommandBuffer cb) { 4569 VkBool32 skipCall = VK_FALSE; 4570 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb); 4571 if (pCB && pCB->lastBoundDescriptorSet) { 4572 SET_NODE *pSet = getSetNode(my_data, pCB->lastBoundDescriptorSet); 4573 DESCRIPTOR_POOL_NODE *pPool = getPoolNode(my_data, pSet->pool); 4574 // Print out pool details 4575 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4576 DRAWSTATE_NONE, "DS", "Details for pool %#" PRIxLEAST64 ".", (uint64_t)pPool->pool); 4577 string poolStr = vk_print_vkdescriptorpoolcreateinfo(&pPool->createInfo, " "); 4578 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4579 DRAWSTATE_NONE, "DS", "%s", poolStr.c_str()); 4580 // Print out set details 4581 char prefix[10]; 4582 uint32_t index = 0; 4583 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4584 DRAWSTATE_NONE, "DS", "Details for descriptor set %#" PRIxLEAST64 ".", (uint64_t)pSet->set); 4585 LAYOUT_NODE *pLayout = pSet->pLayout; 4586 // Print layout details 4587 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4588 DRAWSTATE_NONE, "DS", "Layout #%u, (object %#" PRIxLEAST64 ") for DS %#" PRIxLEAST64 ".", index + 1, 4589 (uint64_t)(pLayout->layout), (uint64_t)(pSet->set)); 4590 sprintf(prefix, " [L%u] ", index); 4591 string DSLstr = vk_print_vkdescriptorsetlayoutcreateinfo(&pLayout->createInfo, prefix).c_str(); 4592 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4593 DRAWSTATE_NONE, "DS", "%s", DSLstr.c_str()); 4594 index++; 4595 GENERIC_HEADER *pUpdate = pSet->pUpdateStructs; 4596 if (pUpdate) { 4597 skipCall |= 4598 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4599 DRAWSTATE_NONE, "DS", "Update Chain [UC] for descriptor set %#" PRIxLEAST64 ":", (uint64_t)pSet->set); 4600 sprintf(prefix, " [UC] "); 4601 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 4602 __LINE__, DRAWSTATE_NONE, "DS", "%s", dynamic_display(pUpdate, prefix).c_str()); 4603 // TODO : If there is a "view" associated with this update, print CI for that view 4604 } else { 4605 if (0 != pSet->descriptorCount) { 4606 skipCall |= 4607 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4608 DRAWSTATE_NONE, "DS", "No Update Chain for descriptor set %#" PRIxLEAST64 4609 " which has %u descriptors (vkUpdateDescriptors has not been called)", 4610 (uint64_t)pSet->set, pSet->descriptorCount); 4611 } else { 4612 skipCall |= 4613 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4614 DRAWSTATE_NONE, "DS", "FYI: No descriptors in descriptor set %#" PRIxLEAST64 ".", (uint64_t)pSet->set); 4615 } 4616 } 4617 } 4618 return skipCall; 4619} 4620 4621static void printCB(layer_data *my_data, const VkCommandBuffer cb) { 4622 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb); 4623 if (pCB && pCB->cmds.size() > 0) { 4624 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 4625 DRAWSTATE_NONE, "DS", "Cmds in CB %p", (void *)cb); 4626 vector<CMD_NODE> cmds = pCB->cmds; 4627 for (auto ii = cmds.begin(); ii != cmds.end(); ++ii) { 4628 // TODO : Need to pass cb as srcObj here 4629 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 4630 __LINE__, DRAWSTATE_NONE, "DS", " CMD#%" PRIu64 ": %s", (*ii).cmdNumber, cmdTypeToString((*ii).type).c_str()); 4631 } 4632 } else { 4633 // Nothing to print 4634 } 4635} 4636 4637static VkBool32 synchAndPrintDSConfig(layer_data *my_data, const VkCommandBuffer cb) { 4638 VkBool32 skipCall = VK_FALSE; 4639 if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) { 4640 return skipCall; 4641 } 4642 skipCall |= printDSConfig(my_data, cb); 4643 skipCall |= printPipeline(my_data, cb); 4644 return skipCall; 4645} 4646 4647// Flags validation error if the associated call is made inside a render pass. The apiName 4648// routine should ONLY be called outside a render pass. 4649static VkBool32 insideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) { 4650 VkBool32 inside = VK_FALSE; 4651 if (pCB->activeRenderPass) { 4652 inside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 4653 (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS", 4654 "%s: It is invalid to issue this call inside an active render pass (%#" PRIxLEAST64 ")", apiName, 4655 (uint64_t)pCB->activeRenderPass); 4656 } 4657 return inside; 4658} 4659 4660// Flags validation error if the associated call is made outside a render pass. The apiName 4661// routine should ONLY be called inside a render pass. 4662static VkBool32 outsideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) { 4663 VkBool32 outside = VK_FALSE; 4664 if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) || 4665 ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) && 4666 !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) { 4667 outside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 4668 (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS", 4669 "%s: This call must be issued inside an active render pass.", apiName); 4670 } 4671 return outside; 4672} 4673 4674static void init_core_validation(layer_data *my_data, const VkAllocationCallbacks *pAllocator) { 4675 4676 layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_core_validation"); 4677 4678 if (!globalLockInitialized) { 4679 loader_platform_thread_create_mutex(&globalLock); 4680 globalLockInitialized = 1; 4681 } 4682#if MTMERGE 4683 // Zero out memory property data 4684 memset(&memProps, 0, sizeof(VkPhysicalDeviceMemoryProperties)); 4685#endif 4686} 4687 4688VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 4689vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) { 4690 VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); 4691 4692 assert(chain_info->u.pLayerInfo); 4693 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; 4694 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance"); 4695 if (fpCreateInstance == NULL) 4696 return VK_ERROR_INITIALIZATION_FAILED; 4697 4698 // Advance the link info for the next element on the chain 4699 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; 4700 4701 VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance); 4702 if (result != VK_SUCCESS) 4703 return result; 4704 4705 layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map); 4706 my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable; 4707 layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr); 4708 4709 my_data->report_data = debug_report_create_instance(my_data->instance_dispatch_table, *pInstance, 4710 pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames); 4711 4712 init_core_validation(my_data, pAllocator); 4713 4714 ValidateLayerOrdering(*pCreateInfo); 4715 4716 return result; 4717} 4718 4719/* hook DestroyInstance to remove tableInstanceMap entry */ 4720VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) { 4721 // TODOSC : Shouldn't need any customization here 4722 dispatch_key key = get_dispatch_key(instance); 4723 // TBD: Need any locking this early, in case this function is called at the 4724 // same time by more than one thread? 4725 layer_data *my_data = get_my_data_ptr(key, layer_data_map); 4726 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; 4727 pTable->DestroyInstance(instance, pAllocator); 4728 4729 loader_platform_thread_lock_mutex(&globalLock); 4730 // Clean up logging callback, if any 4731 while (my_data->logging_callback.size() > 0) { 4732 VkDebugReportCallbackEXT callback = my_data->logging_callback.back(); 4733 layer_destroy_msg_callback(my_data->report_data, callback, pAllocator); 4734 my_data->logging_callback.pop_back(); 4735 } 4736 4737 layer_debug_report_destroy_instance(my_data->report_data); 4738 delete my_data->instance_dispatch_table; 4739 layer_data_map.erase(key); 4740 loader_platform_thread_unlock_mutex(&globalLock); 4741 if (layer_data_map.empty()) { 4742 // Release mutex when destroying last instance. 4743 loader_platform_thread_delete_mutex(&globalLock); 4744 globalLockInitialized = 0; 4745 } 4746} 4747 4748static void createDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) { 4749 uint32_t i; 4750 // TBD: Need any locking, in case this function is called at the same time 4751 // by more than one thread? 4752 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 4753 dev_data->device_extensions.wsi_enabled = false; 4754 4755 VkLayerDispatchTable *pDisp = dev_data->device_dispatch_table; 4756 PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr; 4757 pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpa(device, "vkCreateSwapchainKHR"); 4758 pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)gpa(device, "vkDestroySwapchainKHR"); 4759 pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)gpa(device, "vkGetSwapchainImagesKHR"); 4760 pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)gpa(device, "vkAcquireNextImageKHR"); 4761 pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR)gpa(device, "vkQueuePresentKHR"); 4762 4763 for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) { 4764 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) 4765 dev_data->device_extensions.wsi_enabled = true; 4766 } 4767} 4768 4769VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, 4770 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) { 4771 VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); 4772 4773 assert(chain_info->u.pLayerInfo); 4774 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; 4775 PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr; 4776 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice"); 4777 if (fpCreateDevice == NULL) { 4778 return VK_ERROR_INITIALIZATION_FAILED; 4779 } 4780 4781 // Advance the link info for the next element on the chain 4782 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; 4783 4784 VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice); 4785 if (result != VK_SUCCESS) { 4786 return result; 4787 } 4788 4789 loader_platform_thread_lock_mutex(&globalLock); 4790 layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map); 4791 layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map); 4792 4793 // Setup device dispatch table 4794 my_device_data->device_dispatch_table = new VkLayerDispatchTable; 4795 layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr); 4796 4797 my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice); 4798 createDeviceRegisterExtensions(pCreateInfo, *pDevice); 4799 // Get physical device limits for this device 4800 my_instance_data->instance_dispatch_table->GetPhysicalDeviceProperties(gpu, &(my_device_data->physDevProperties.properties)); 4801 uint32_t count; 4802 my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr); 4803 my_device_data->physDevProperties.queue_family_properties.resize(count); 4804 my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties( 4805 gpu, &count, &my_device_data->physDevProperties.queue_family_properties[0]); 4806 // TODO: device limits should make sure these are compatible 4807 if (pCreateInfo->pEnabledFeatures) { 4808 my_device_data->physDevProperties.features = *pCreateInfo->pEnabledFeatures; 4809 } else { 4810 memset(&my_device_data->physDevProperties.features, 0, sizeof(VkPhysicalDeviceFeatures)); 4811 } 4812 loader_platform_thread_unlock_mutex(&globalLock); 4813 4814 ValidateLayerOrdering(*pCreateInfo); 4815 4816 return result; 4817} 4818 4819// prototype 4820static void deleteRenderPasses(layer_data *); 4821VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) { 4822 // TODOSC : Shouldn't need any customization here 4823 dispatch_key key = get_dispatch_key(device); 4824 layer_data *dev_data = get_my_data_ptr(key, layer_data_map); 4825 // Free all the memory 4826 loader_platform_thread_lock_mutex(&globalLock); 4827 deletePipelines(dev_data); 4828 deleteRenderPasses(dev_data); 4829 deleteCommandBuffers(dev_data); 4830 deletePools(dev_data); 4831 deleteLayouts(dev_data); 4832 dev_data->imageViewMap.clear(); 4833 dev_data->imageMap.clear(); 4834 dev_data->imageSubresourceMap.clear(); 4835 dev_data->imageLayoutMap.clear(); 4836 dev_data->bufferViewMap.clear(); 4837 dev_data->bufferMap.clear(); 4838 loader_platform_thread_unlock_mutex(&globalLock); 4839#if MTMERGE 4840 VkBool32 skipCall = VK_FALSE; 4841 loader_platform_thread_lock_mutex(&globalLock); 4842 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 4843 (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "Printing List details prior to vkDestroyDevice()"); 4844 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 4845 (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "================================================"); 4846 print_mem_list(dev_data, device); 4847 printCBList(dev_data, device); 4848 skipCall = delete_cmd_buf_info_list(dev_data); 4849 // Report any memory leaks 4850 DEVICE_MEM_INFO *pInfo = NULL; 4851 if (dev_data->memObjMap.size() > 0) { 4852 for (auto ii = dev_data->memObjMap.begin(); ii != dev_data->memObjMap.end(); ++ii) { 4853 pInfo = &(*ii).second; 4854 if (pInfo->allocInfo.allocationSize != 0) { 4855 // Valid Usage: All child objects created on device must have been destroyed prior to destroying device 4856 skipCall |= 4857 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 4858 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pInfo->mem, __LINE__, MEMTRACK_MEMORY_LEAK, 4859 "MEM", "Mem Object %" PRIu64 " has not been freed. You should clean up this memory by calling " 4860 "vkFreeMemory(%" PRIu64 ") prior to vkDestroyDevice().", 4861 (uint64_t)(pInfo->mem), (uint64_t)(pInfo->mem)); 4862 } 4863 } 4864 } 4865 // Queues persist until device is destroyed 4866 delete_queue_info_list(dev_data); 4867 layer_debug_report_destroy_device(device); 4868 loader_platform_thread_unlock_mutex(&globalLock); 4869 4870#if DISPATCH_MAP_DEBUG 4871 fprintf(stderr, "Device: %p, key: %p\n", device, key); 4872#endif 4873 VkLayerDispatchTable *pDisp = dev_data->device_dispatch_table; 4874 if (VK_FALSE == skipCall) { 4875 pDisp->DestroyDevice(device, pAllocator); 4876 } 4877#else 4878 dev_data->device_dispatch_table->DestroyDevice(device, pAllocator); 4879#endif 4880 delete dev_data->device_dispatch_table; 4881 layer_data_map.erase(key); 4882} 4883 4884#if MTMERGE 4885VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 4886vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties) { 4887 layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map); 4888 VkLayerInstanceDispatchTable *pInstanceTable = my_data->instance_dispatch_table; 4889 pInstanceTable->GetPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties); 4890 memcpy(&memProps, pMemoryProperties, sizeof(VkPhysicalDeviceMemoryProperties)); 4891} 4892#endif 4893 4894static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}}; 4895 4896VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 4897vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties) { 4898 return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties); 4899} 4900 4901VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 4902vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) { 4903 return util_GetLayerProperties(ARRAY_SIZE(cv_global_layers), cv_global_layers, pCount, pProperties); 4904} 4905 4906// TODO: Why does this exist - can we just use global? 4907static const VkLayerProperties cv_device_layers[] = {{ 4908 "VK_LAYER_LUNARG_core_validation", VK_API_VERSION, 1, "LunarG Validation Layer", 4909}}; 4910 4911VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, 4912 const char *pLayerName, uint32_t *pCount, 4913 VkExtensionProperties *pProperties) { 4914 if (pLayerName == NULL) { 4915 dispatch_key key = get_dispatch_key(physicalDevice); 4916 layer_data *my_data = get_my_data_ptr(key, layer_data_map); 4917 return my_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties); 4918 } else { 4919 return util_GetExtensionProperties(0, NULL, pCount, pProperties); 4920 } 4921} 4922 4923VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 4924vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties) { 4925 /* draw_state physical device layers are the same as global */ 4926 return util_GetLayerProperties(ARRAY_SIZE(cv_device_layers), cv_device_layers, pCount, pProperties); 4927} 4928 4929// This validates that the initial layout specified in the command buffer for 4930// the IMAGE is the same 4931// as the global IMAGE layout 4932VkBool32 ValidateCmdBufImageLayouts(VkCommandBuffer cmdBuffer) { 4933 VkBool32 skip_call = VK_FALSE; 4934 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 4935 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 4936 for (auto cb_image_data : pCB->imageLayoutMap) { 4937 VkImageLayout imageLayout; 4938 if (!FindLayout(dev_data, cb_image_data.first, imageLayout)) { 4939 skip_call |= 4940 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 4941 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot submit cmd buffer using deleted image %" PRIu64 ".", 4942 reinterpret_cast<const uint64_t &>(cb_image_data.first)); 4943 } else { 4944 if (cb_image_data.second.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) { 4945 // TODO: Set memory invalid which is in mem_tracker currently 4946 } else if (imageLayout != cb_image_data.second.initialLayout) { 4947 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 4948 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, 4949 "DS", "Cannot submit cmd buffer using image with layout %s when " 4950 "first use is %s.", 4951 string_VkImageLayout(imageLayout), string_VkImageLayout(cb_image_data.second.initialLayout)); 4952 } 4953 SetLayout(dev_data, cb_image_data.first, cb_image_data.second.layout); 4954 } 4955 } 4956 return skip_call; 4957} 4958// Track which resources are in-flight by atomically incrementing their "in_use" count 4959VkBool32 validateAndIncrementResources(layer_data *my_data, GLOBAL_CB_NODE *pCB) { 4960 VkBool32 skip_call = VK_FALSE; 4961 for (auto drawDataElement : pCB->drawData) { 4962 for (auto buffer : drawDataElement.buffers) { 4963 auto buffer_data = my_data->bufferMap.find(buffer); 4964 if (buffer_data == my_data->bufferMap.end()) { 4965 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, 4966 (uint64_t)(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS", 4967 "Cannot submit cmd buffer using deleted buffer %" PRIu64 ".", (uint64_t)(buffer)); 4968 } else { 4969 buffer_data->second.in_use.fetch_add(1); 4970 } 4971 } 4972 } 4973 for (auto set : pCB->uniqueBoundSets) { 4974 auto setNode = my_data->setMap.find(set); 4975 if (setNode == my_data->setMap.end()) { 4976 skip_call |= 4977 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4978 (uint64_t)(set), __LINE__, DRAWSTATE_INVALID_DESCRIPTOR_SET, "DS", 4979 "Cannot submit cmd buffer using deleted descriptor set %" PRIu64 ".", (uint64_t)(set)); 4980 } else { 4981 setNode->second->in_use.fetch_add(1); 4982 } 4983 } 4984 for (auto semaphore : pCB->semaphores) { 4985 auto semaphoreNode = my_data->semaphoreMap.find(semaphore); 4986 if (semaphoreNode == my_data->semaphoreMap.end()) { 4987 skip_call |= 4988 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 4989 reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS", 4990 "Cannot submit cmd buffer using deleted semaphore %" PRIu64 ".", reinterpret_cast<uint64_t &>(semaphore)); 4991 } else { 4992 semaphoreNode->second.in_use.fetch_add(1); 4993 } 4994 } 4995 for (auto event : pCB->events) { 4996 auto eventNode = my_data->eventMap.find(event); 4997 if (eventNode == my_data->eventMap.end()) { 4998 skip_call |= 4999 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 5000 reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS", 5001 "Cannot submit cmd buffer using deleted event %" PRIu64 ".", reinterpret_cast<uint64_t &>(event)); 5002 } else { 5003 eventNode->second.in_use.fetch_add(1); 5004 } 5005 } 5006 return skip_call; 5007} 5008 5009void decrementResources(layer_data *my_data, VkCommandBuffer cmdBuffer) { 5010 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer); 5011 for (auto drawDataElement : pCB->drawData) { 5012 for (auto buffer : drawDataElement.buffers) { 5013 auto buffer_data = my_data->bufferMap.find(buffer); 5014 if (buffer_data != my_data->bufferMap.end()) { 5015 buffer_data->second.in_use.fetch_sub(1); 5016 } 5017 } 5018 } 5019 for (auto set : pCB->uniqueBoundSets) { 5020 auto setNode = my_data->setMap.find(set); 5021 if (setNode != my_data->setMap.end()) { 5022 setNode->second->in_use.fetch_sub(1); 5023 } 5024 } 5025 for (auto semaphore : pCB->semaphores) { 5026 auto semaphoreNode = my_data->semaphoreMap.find(semaphore); 5027 if (semaphoreNode != my_data->semaphoreMap.end()) { 5028 semaphoreNode->second.in_use.fetch_sub(1); 5029 } 5030 } 5031 for (auto event : pCB->events) { 5032 auto eventNode = my_data->eventMap.find(event); 5033 if (eventNode != my_data->eventMap.end()) { 5034 eventNode->second.in_use.fetch_sub(1); 5035 } 5036 } 5037 for (auto queryStatePair : pCB->queryToStateMap) { 5038 my_data->queryToStateMap[queryStatePair.first] = queryStatePair.second; 5039 } 5040 for (auto eventStagePair : pCB->eventToStageMap) { 5041 my_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second; 5042 } 5043} 5044 5045void decrementResources(layer_data *my_data, uint32_t fenceCount, const VkFence *pFences) { 5046 for (uint32_t i = 0; i < fenceCount; ++i) { 5047 auto fence_data = my_data->fenceMap.find(pFences[i]); 5048 if (fence_data == my_data->fenceMap.end() || !fence_data->second.needsSignaled) 5049 return; 5050 fence_data->second.needsSignaled = false; 5051 fence_data->second.in_use.fetch_sub(1); 5052 if (fence_data->second.priorFence != VK_NULL_HANDLE) { 5053 decrementResources(my_data, 1, &fence_data->second.priorFence); 5054 } 5055 for (auto cmdBuffer : fence_data->second.cmdBuffers) { 5056 decrementResources(my_data, cmdBuffer); 5057 } 5058 } 5059} 5060 5061void decrementResources(layer_data *my_data, VkQueue queue) { 5062 auto queue_data = my_data->queueMap.find(queue); 5063 if (queue_data != my_data->queueMap.end()) { 5064 for (auto cmdBuffer : queue_data->second.untrackedCmdBuffers) { 5065 decrementResources(my_data, cmdBuffer); 5066 } 5067 queue_data->second.untrackedCmdBuffers.clear(); 5068 decrementResources(my_data, 1, &queue_data->second.priorFence); 5069 } 5070} 5071 5072void trackCommandBuffers(layer_data *my_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) { 5073 auto queue_data = my_data->queueMap.find(queue); 5074 if (fence != VK_NULL_HANDLE) { 5075 VkFence priorFence = VK_NULL_HANDLE; 5076 auto fence_data = my_data->fenceMap.find(fence); 5077 if (fence_data == my_data->fenceMap.end()) { 5078 return; 5079 } 5080 if (queue_data != my_data->queueMap.end()) { 5081 priorFence = queue_data->second.priorFence; 5082 queue_data->second.priorFence = fence; 5083 for (auto cmdBuffer : queue_data->second.untrackedCmdBuffers) { 5084 fence_data->second.cmdBuffers.push_back(cmdBuffer); 5085 } 5086 queue_data->second.untrackedCmdBuffers.clear(); 5087 } 5088 fence_data->second.cmdBuffers.clear(); 5089 fence_data->second.priorFence = priorFence; 5090 fence_data->second.needsSignaled = true; 5091 fence_data->second.queue = queue; 5092 fence_data->second.in_use.fetch_add(1); 5093 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5094 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5095 for (uint32_t i = 0; i < submit->commandBufferCount; ++i) { 5096 for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) { 5097 fence_data->second.cmdBuffers.push_back(secondaryCmdBuffer); 5098 } 5099 fence_data->second.cmdBuffers.push_back(submit->pCommandBuffers[i]); 5100 } 5101 } 5102 } else { 5103 if (queue_data != my_data->queueMap.end()) { 5104 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5105 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5106 for (uint32_t i = 0; i < submit->commandBufferCount; ++i) { 5107 for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) { 5108 queue_data->second.untrackedCmdBuffers.push_back(secondaryCmdBuffer); 5109 } 5110 queue_data->second.untrackedCmdBuffers.push_back(submit->pCommandBuffers[i]); 5111 } 5112 } 5113 } 5114 } 5115 if (queue_data != my_data->queueMap.end()) { 5116 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5117 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5118 for (uint32_t i = 0; i < submit->commandBufferCount; ++i) { 5119 // Add cmdBuffers to both the global set and queue set 5120 for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) { 5121 my_data->globalInFlightCmdBuffers.insert(secondaryCmdBuffer); 5122 queue_data->second.inFlightCmdBuffers.insert(secondaryCmdBuffer); 5123 } 5124 my_data->globalInFlightCmdBuffers.insert(submit->pCommandBuffers[i]); 5125 queue_data->second.inFlightCmdBuffers.insert(submit->pCommandBuffers[i]); 5126 } 5127 } 5128 } 5129} 5130 5131bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB) { 5132 bool skip_call = false; 5133 if (dev_data->globalInFlightCmdBuffers.count(pCB->commandBuffer) && 5134 !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) { 5135 skip_call |= 5136 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 5137 __LINE__, DRAWSTATE_INVALID_FENCE, "DS", "Command Buffer %#" PRIx64 " is already in use and is not marked " 5138 "for simultaneous use.", 5139 reinterpret_cast<uint64_t>(pCB->commandBuffer)); 5140 } 5141 return skip_call; 5142} 5143 5144static bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) { 5145 bool skipCall = false; 5146 // Validate that cmd buffers have been updated 5147 if (CB_RECORDED != pCB->state) { 5148 if (CB_INVALID == pCB->state) { 5149 // Inform app of reason CB invalid 5150 bool causeReported = false; 5151 if (!pCB->destroyedSets.empty()) { 5152 std::stringstream set_string; 5153 for (auto set : pCB->destroyedSets) 5154 set_string << " " << set; 5155 5156 skipCall |= 5157 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 5158 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 5159 "You are submitting command buffer %#" PRIxLEAST64 5160 " that is invalid because it had the following bound descriptor set(s) destroyed: %s", 5161 (uint64_t)(pCB->commandBuffer), set_string.str().c_str()); 5162 causeReported = true; 5163 } 5164 if (!pCB->updatedSets.empty()) { 5165 std::stringstream set_string; 5166 for (auto set : pCB->updatedSets) 5167 set_string << " " << set; 5168 5169 skipCall |= 5170 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 5171 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 5172 "You are submitting command buffer %#" PRIxLEAST64 5173 " that is invalid because it had the following bound descriptor set(s) updated: %s", 5174 (uint64_t)(pCB->commandBuffer), set_string.str().c_str()); 5175 causeReported = true; 5176 } 5177 if (!pCB->destroyedFramebuffers.empty()) { 5178 std::stringstream fb_string; 5179 for (auto fb : pCB->destroyedFramebuffers) 5180 fb_string << " " << fb; 5181 5182 skipCall |= 5183 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 5184 reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 5185 "You are submitting command buffer %#" PRIxLEAST64 " that is invalid because it had the following " 5186 "referenced framebuffers destroyed: %s", 5187 reinterpret_cast<uint64_t &>(pCB->commandBuffer), fb_string.str().c_str()); 5188 causeReported = true; 5189 } 5190 // TODO : This is defensive programming to make sure an error is 5191 // flagged if we hit this INVALID cmd buffer case and none of the 5192 // above cases are hit. As the number of INVALID cases grows, this 5193 // code should be updated to seemlessly handle all the cases. 5194 if (!causeReported) { 5195 skipCall |= log_msg( 5196 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 5197 reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 5198 "You are submitting command buffer %#" PRIxLEAST64 " that is invalid due to an unknown cause. Validation " 5199 "should " 5200 "be improved to report the exact cause.", 5201 reinterpret_cast<uint64_t &>(pCB->commandBuffer)); 5202 } 5203 } else { // Flag error for using CB w/o vkEndCommandBuffer() called 5204 skipCall |= 5205 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 5206 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS", 5207 "You must call vkEndCommandBuffer() on CB %#" PRIxLEAST64 " before this call to vkQueueSubmit()!", 5208 (uint64_t)(pCB->commandBuffer)); 5209 } 5210 } 5211 return skipCall; 5212} 5213 5214static VkBool32 validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) { 5215 // Track in-use for resources off of primary and any secondary CBs 5216 VkBool32 skipCall = validateAndIncrementResources(dev_data, pCB); 5217 if (!pCB->secondaryCommandBuffers.empty()) { 5218 for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) { 5219 skipCall |= validateAndIncrementResources(dev_data, dev_data->commandBufferMap[secondaryCmdBuffer]); 5220 GLOBAL_CB_NODE *pSubCB = getCBNode(dev_data, secondaryCmdBuffer); 5221 if (pSubCB->primaryCommandBuffer != pCB->commandBuffer) { 5222 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 5223 __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS", 5224 "CB %#" PRIxLEAST64 " was submitted with secondary buffer %#" PRIxLEAST64 5225 " but that buffer has subsequently been bound to " 5226 "primary cmd buffer %#" PRIxLEAST64 ".", 5227 reinterpret_cast<uint64_t>(pCB->commandBuffer), reinterpret_cast<uint64_t>(secondaryCmdBuffer), 5228 reinterpret_cast<uint64_t>(pSubCB->primaryCommandBuffer)); 5229 } 5230 } 5231 } 5232 // TODO : Verify if this also needs to be checked for secondary command 5233 // buffers. If so, this block of code can move to 5234 // validateCommandBufferState() function. vulkan GL106 filed to clarify 5235 if ((pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) && (pCB->submitCount > 1)) { 5236 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 5237 __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS", 5238 "CB %#" PRIxLEAST64 " was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT " 5239 "set, but has been submitted %#" PRIxLEAST64 " times.", 5240 (uint64_t)(pCB->commandBuffer), pCB->submitCount); 5241 } 5242 skipCall |= validateCommandBufferState(dev_data, pCB); 5243 // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing 5244 // on device 5245 skipCall |= validateCommandBufferSimultaneousUse(dev_data, pCB); 5246 return skipCall; 5247} 5248 5249VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 5250vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) { 5251 VkBool32 skipCall = VK_FALSE; 5252 GLOBAL_CB_NODE *pCB = NULL; 5253 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); 5254 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 5255 loader_platform_thread_lock_mutex(&globalLock); 5256#if MTMERGE 5257 // TODO : Need to track fence and clear mem references when fence clears 5258 // MTMTODO : Merge this code with code below to avoid duplicating efforts 5259 MT_CB_INFO *pCBInfo = NULL; 5260 uint64_t fenceId = 0; 5261 skipCall = add_fence_info(dev_data, fence, queue, &fenceId); 5262 5263 print_mem_list(dev_data, queue); 5264 printCBList(dev_data, queue); 5265 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5266 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5267 for (uint32_t i = 0; i < submit->commandBufferCount; i++) { 5268 pCBInfo = get_cmd_buf_info(dev_data, submit->pCommandBuffers[i]); 5269 if (pCBInfo) { 5270 pCBInfo->fenceId = fenceId; 5271 pCBInfo->lastSubmittedFence = fence; 5272 pCBInfo->lastSubmittedQueue = queue; 5273 for (auto &function : pCBInfo->validate_functions) { 5274 skipCall |= function(); 5275 } 5276 } 5277 } 5278 5279 for (uint32_t i = 0; i < submit->waitSemaphoreCount; i++) { 5280 VkSemaphore sem = submit->pWaitSemaphores[i]; 5281 5282 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 5283 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_SIGNALLED) { 5284 skipCall = 5285 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, 5286 (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE", 5287 "vkQueueSubmit: Semaphore must be in signaled state before passing to pWaitSemaphores"); 5288 } 5289 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_WAIT; 5290 } 5291 } 5292 for (uint32_t i = 0; i < submit->signalSemaphoreCount; i++) { 5293 VkSemaphore sem = submit->pSignalSemaphores[i]; 5294 5295 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 5296 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_UNSET) { 5297 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5298 VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, (uint64_t)sem, __LINE__, MEMTRACK_NONE, 5299 "SEMAPHORE", "vkQueueSubmit: Semaphore must not be currently signaled or in a wait state"); 5300 } 5301 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_SIGNALLED; 5302 } 5303 } 5304 } 5305#endif 5306 // First verify that fence is not in use 5307 if ((fence != VK_NULL_HANDLE) && (submitCount != 0) && dev_data->fenceMap[fence].in_use.load()) { 5308 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 5309 (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", 5310 "Fence %#" PRIx64 " is already in use by another submission.", (uint64_t)(fence)); 5311 } 5312 // Now verify each individual submit 5313 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5314 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5315 vector<VkSemaphore> semaphoreList; 5316 for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) { 5317 semaphoreList.push_back(submit->pWaitSemaphores[i]); 5318 if (dev_data->semaphoreMap[submit->pWaitSemaphores[i]].signaled) { 5319 dev_data->semaphoreMap[submit->pWaitSemaphores[i]].signaled = 0; 5320 } else { 5321 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5322 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, 5323 "DS", "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.", 5324 (uint64_t)(queue), (uint64_t)(submit->pWaitSemaphores[i])); 5325 } 5326 } 5327 for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) { 5328 semaphoreList.push_back(submit->pSignalSemaphores[i]); 5329 dev_data->semaphoreMap[submit->pSignalSemaphores[i]].signaled = 1; 5330 } 5331 for (uint32_t i = 0; i < submit->commandBufferCount; i++) { 5332 skipCall |= ValidateCmdBufImageLayouts(submit->pCommandBuffers[i]); 5333 pCB = getCBNode(dev_data, submit->pCommandBuffers[i]); 5334 pCB->semaphores = semaphoreList; 5335 pCB->submitCount++; // increment submit count 5336 skipCall |= validatePrimaryCommandBufferState(dev_data, pCB); 5337 } 5338 } 5339 // Update cmdBuffer-related data structs and mark fence in-use 5340 trackCommandBuffers(dev_data, queue, submitCount, pSubmits, fence); 5341 loader_platform_thread_unlock_mutex(&globalLock); 5342 if (VK_FALSE == skipCall) 5343 result = dev_data->device_dispatch_table->QueueSubmit(queue, submitCount, pSubmits, fence); 5344#if MTMERGE 5345 loader_platform_thread_lock_mutex(&globalLock); 5346 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { 5347 const VkSubmitInfo *submit = &pSubmits[submit_idx]; 5348 for (uint32_t i = 0; i < submit->waitSemaphoreCount; i++) { 5349 VkSemaphore sem = submit->pWaitSemaphores[i]; 5350 5351 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 5352 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_UNSET; 5353 } 5354 } 5355 } 5356 loader_platform_thread_unlock_mutex(&globalLock); 5357#endif 5358 return result; 5359} 5360 5361#if MTMERGE 5362VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, 5363 const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) { 5364 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5365 VkResult result = my_data->device_dispatch_table->AllocateMemory(device, pAllocateInfo, pAllocator, pMemory); 5366 // TODO : Track allocations and overall size here 5367 loader_platform_thread_lock_mutex(&globalLock); 5368 add_mem_obj_info(my_data, device, *pMemory, pAllocateInfo); 5369 print_mem_list(my_data, device); 5370 loader_platform_thread_unlock_mutex(&globalLock); 5371 return result; 5372} 5373 5374VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5375vkFreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) { 5376 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5377 5378 // From spec : A memory object is freed by calling vkFreeMemory() when it is no longer needed. 5379 // Before freeing a memory object, an application must ensure the memory object is no longer 5380 // in use by the device—for example by command buffers queued for execution. The memory need 5381 // not yet be unbound from all images and buffers, but any further use of those images or 5382 // buffers (on host or device) for anything other than destroying those objects will result in 5383 // undefined behavior. 5384 5385 loader_platform_thread_lock_mutex(&globalLock); 5386 freeMemObjInfo(my_data, device, mem, VK_FALSE); 5387 print_mem_list(my_data, device); 5388 printCBList(my_data, device); 5389 loader_platform_thread_unlock_mutex(&globalLock); 5390 my_data->device_dispatch_table->FreeMemory(device, mem, pAllocator); 5391} 5392 5393VkBool32 validateMemRange(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) { 5394 VkBool32 skipCall = VK_FALSE; 5395 5396 if (size == 0) { 5397 // TODO: a size of 0 is not listed as an invalid use in the spec, should it be? 5398 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 5399 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM", 5400 "VkMapMemory: Attempting to map memory range of size zero"); 5401 } 5402 5403 auto mem_element = my_data->memObjMap.find(mem); 5404 if (mem_element != my_data->memObjMap.end()) { 5405 // It is an application error to call VkMapMemory on an object that is already mapped 5406 if (mem_element->second.memRange.size != 0) { 5407 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 5408 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM", 5409 "VkMapMemory: Attempting to map memory on an already-mapped object %#" PRIxLEAST64, (uint64_t)mem); 5410 } 5411 5412 // Validate that offset + size is within object's allocationSize 5413 if (size == VK_WHOLE_SIZE) { 5414 if (offset >= mem_element->second.allocInfo.allocationSize) { 5415 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5416 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, 5417 "MEM", "Mapping Memory from %" PRIu64 " to %" PRIu64 " with total array size %" PRIu64, offset, 5418 mem_element->second.allocInfo.allocationSize, mem_element->second.allocInfo.allocationSize); 5419 } 5420 } else { 5421 if ((offset + size) > mem_element->second.allocInfo.allocationSize) { 5422 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5423 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, 5424 "MEM", "Mapping Memory from %" PRIu64 " to %" PRIu64 " with total array size %" PRIu64, offset, 5425 size + offset, mem_element->second.allocInfo.allocationSize); 5426 } 5427 } 5428 } 5429 return skipCall; 5430} 5431 5432void storeMemRanges(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) { 5433 auto mem_element = my_data->memObjMap.find(mem); 5434 if (mem_element != my_data->memObjMap.end()) { 5435 MemRange new_range; 5436 new_range.offset = offset; 5437 new_range.size = size; 5438 mem_element->second.memRange = new_range; 5439 } 5440} 5441 5442VkBool32 deleteMemRanges(layer_data *my_data, VkDeviceMemory mem) { 5443 VkBool32 skipCall = VK_FALSE; 5444 auto mem_element = my_data->memObjMap.find(mem); 5445 if (mem_element != my_data->memObjMap.end()) { 5446 if (!mem_element->second.memRange.size) { 5447 // Valid Usage: memory must currently be mapped 5448 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 5449 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM", 5450 "Unmapping Memory without memory being mapped: mem obj %#" PRIxLEAST64, (uint64_t)mem); 5451 } 5452 mem_element->second.memRange.size = 0; 5453 if (mem_element->second.pData) { 5454 free(mem_element->second.pData); 5455 mem_element->second.pData = 0; 5456 } 5457 } 5458 return skipCall; 5459} 5460 5461static char NoncoherentMemoryFillValue = 0xb; 5462 5463void initializeAndTrackMemory(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize size, void **ppData) { 5464 auto mem_element = my_data->memObjMap.find(mem); 5465 if (mem_element != my_data->memObjMap.end()) { 5466 mem_element->second.pDriverData = *ppData; 5467 uint32_t index = mem_element->second.allocInfo.memoryTypeIndex; 5468 if (memProps.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { 5469 mem_element->second.pData = 0; 5470 } else { 5471 if (size == VK_WHOLE_SIZE) { 5472 size = mem_element->second.allocInfo.allocationSize; 5473 } 5474 size_t convSize = (size_t)(size); 5475 mem_element->second.pData = malloc(2 * convSize); 5476 memset(mem_element->second.pData, NoncoherentMemoryFillValue, 2 * convSize); 5477 *ppData = static_cast<char *>(mem_element->second.pData) + (convSize / 2); 5478 } 5479 } 5480} 5481#endif 5482// Note: This function assumes that the global lock is held by the calling 5483// thread. 5484VkBool32 cleanInFlightCmdBuffer(layer_data *my_data, VkCommandBuffer cmdBuffer) { 5485 VkBool32 skip_call = VK_FALSE; 5486 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer); 5487 if (pCB) { 5488 for (auto queryEventsPair : pCB->waitedEventsBeforeQueryReset) { 5489 for (auto event : queryEventsPair.second) { 5490 if (my_data->eventMap[event].needsSignaled) { 5491 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5492 VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS", 5493 "Cannot get query results on queryPool %" PRIu64 5494 " with index %d which was guarded by unsignaled event %" PRIu64 ".", 5495 (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event)); 5496 } 5497 } 5498 } 5499 } 5500 return skip_call; 5501} 5502// Remove given cmd_buffer from the global inFlight set. 5503// Also, if given queue is valid, then remove the cmd_buffer from that queues 5504// inFlightCmdBuffer set. Finally, check all other queues and if given cmd_buffer 5505// is still in flight on another queue, add it back into the global set. 5506// Note: This function assumes that the global lock is held by the calling 5507// thread. 5508static inline void removeInFlightCmdBuffer(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkQueue queue) { 5509 // Pull it off of global list initially, but if we find it in any other queue list, add it back in 5510 dev_data->globalInFlightCmdBuffers.erase(cmd_buffer); 5511 if (dev_data->queueMap.find(queue) != dev_data->queueMap.end()) { 5512 dev_data->queueMap[queue].inFlightCmdBuffers.erase(cmd_buffer); 5513 for (auto q : dev_data->queues) { 5514 if ((q != queue) && 5515 (dev_data->queueMap[q].inFlightCmdBuffers.find(cmd_buffer) != dev_data->queueMap[q].inFlightCmdBuffers.end())) { 5516 dev_data->globalInFlightCmdBuffers.insert(cmd_buffer); 5517 break; 5518 } 5519 } 5520 } 5521} 5522#if MTMERGE 5523static inline bool verifyFenceStatus(VkDevice device, VkFence fence, const char *apiCall) { 5524 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5525 VkBool32 skipCall = false; 5526 auto pFenceInfo = my_data->fenceMap.find(fence); 5527 if (pFenceInfo != my_data->fenceMap.end()) { 5528 if (pFenceInfo->second.firstTimeFlag != VK_TRUE) { 5529 if ((pFenceInfo->second.createInfo.flags & VK_FENCE_CREATE_SIGNALED_BIT) && 5530 pFenceInfo->second.firstTimeFlag != VK_TRUE) { 5531 skipCall |= 5532 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 5533 (uint64_t)fence, __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", 5534 "%s specified fence %#" PRIxLEAST64 " already in SIGNALED state.", apiCall, (uint64_t)fence); 5535 } 5536 if (!pFenceInfo->second.queue && !pFenceInfo->second.swapchain) { // Checking status of unsubmitted fence 5537 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 5538 reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", 5539 "%s called for fence %#" PRIxLEAST64 " which has not been submitted on a Queue or during " 5540 "acquire next image.", 5541 apiCall, reinterpret_cast<uint64_t &>(fence)); 5542 } 5543 } else { 5544 pFenceInfo->second.firstTimeFlag = VK_FALSE; 5545 } 5546 } 5547 return skipCall; 5548} 5549#endif 5550VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 5551vkWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout) { 5552 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5553 VkBool32 skip_call = VK_FALSE; 5554#if MTMERGE 5555 // Verify fence status of submitted fences 5556 loader_platform_thread_lock_mutex(&globalLock); 5557 for (uint32_t i = 0; i < fenceCount; i++) { 5558 skip_call |= verifyFenceStatus(device, pFences[i], "vkWaitForFences"); 5559 } 5560 loader_platform_thread_unlock_mutex(&globalLock); 5561 if (skip_call) 5562 return VK_ERROR_VALIDATION_FAILED_EXT; 5563#endif 5564 VkResult result = dev_data->device_dispatch_table->WaitForFences(device, fenceCount, pFences, waitAll, timeout); 5565 5566 if (result == VK_SUCCESS) { 5567 loader_platform_thread_lock_mutex(&globalLock); 5568 // When we know that all fences are complete we can clean/remove their CBs 5569 if (waitAll || fenceCount == 1) { 5570 for (uint32_t i = 0; i < fenceCount; ++i) { 5571#if MTMERGE 5572 update_fence_tracking(dev_data, pFences[i]); 5573#endif 5574 VkQueue fence_queue = dev_data->fenceMap[pFences[i]].queue; 5575 for (auto cmdBuffer : dev_data->fenceMap[pFences[i]].cmdBuffers) { 5576 skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); 5577 removeInFlightCmdBuffer(dev_data, cmdBuffer, fence_queue); 5578 } 5579 } 5580 decrementResources(dev_data, fenceCount, pFences); 5581 } 5582 // NOTE : Alternate case not handled here is when some fences have completed. In 5583 // this case for app to guarantee which fences completed it will have to call 5584 // vkGetFenceStatus() at which point we'll clean/remove their CBs if complete. 5585 loader_platform_thread_unlock_mutex(&globalLock); 5586 } 5587 if (VK_FALSE != skip_call) 5588 return VK_ERROR_VALIDATION_FAILED_EXT; 5589 return result; 5590} 5591 5592VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus(VkDevice device, VkFence fence) { 5593 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5594 bool skipCall = false; 5595 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 5596#if MTMERGE 5597 loader_platform_thread_lock_mutex(&globalLock); 5598 skipCall = verifyFenceStatus(device, fence, "vkGetFenceStatus"); 5599 loader_platform_thread_unlock_mutex(&globalLock); 5600 if (skipCall) 5601 return result; 5602#endif 5603 result = dev_data->device_dispatch_table->GetFenceStatus(device, fence); 5604 VkBool32 skip_call = VK_FALSE; 5605 loader_platform_thread_lock_mutex(&globalLock); 5606 if (result == VK_SUCCESS) { 5607#if MTMERGE 5608 update_fence_tracking(dev_data, fence); 5609#endif 5610 auto fence_queue = dev_data->fenceMap[fence].queue; 5611 for (auto cmdBuffer : dev_data->fenceMap[fence].cmdBuffers) { 5612 skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); 5613 removeInFlightCmdBuffer(dev_data, cmdBuffer, fence_queue); 5614 } 5615 decrementResources(dev_data, 1, &fence); 5616 } 5617 loader_platform_thread_unlock_mutex(&globalLock); 5618 if (VK_FALSE != skip_call) 5619 return VK_ERROR_VALIDATION_FAILED_EXT; 5620 return result; 5621} 5622 5623VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5624vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) { 5625 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5626 dev_data->device_dispatch_table->GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue); 5627 loader_platform_thread_lock_mutex(&globalLock); 5628 dev_data->queues.push_back(*pQueue); 5629 QUEUE_NODE *pQNode = &dev_data->queueMap[*pQueue]; 5630 pQNode->device = device; 5631#if MTMERGE 5632 pQNode->lastRetiredId = 0; 5633 pQNode->lastSubmittedId = 0; 5634#endif 5635 loader_platform_thread_unlock_mutex(&globalLock); 5636} 5637 5638VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle(VkQueue queue) { 5639 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); 5640 decrementResources(dev_data, queue); 5641 VkBool32 skip_call = VK_FALSE; 5642 loader_platform_thread_lock_mutex(&globalLock); 5643 // Iterate over local set since we erase set members as we go in for loop 5644 auto local_cb_set = dev_data->queueMap[queue].inFlightCmdBuffers; 5645 for (auto cmdBuffer : local_cb_set) { 5646 skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); 5647 removeInFlightCmdBuffer(dev_data, cmdBuffer, queue); 5648 } 5649 dev_data->queueMap[queue].inFlightCmdBuffers.clear(); 5650 loader_platform_thread_unlock_mutex(&globalLock); 5651 if (VK_FALSE != skip_call) 5652 return VK_ERROR_VALIDATION_FAILED_EXT; 5653 VkResult result = dev_data->device_dispatch_table->QueueWaitIdle(queue); 5654#if MTMERGE 5655 if (VK_SUCCESS == result) { 5656 loader_platform_thread_lock_mutex(&globalLock); 5657 retire_queue_fences(dev_data, queue); 5658 loader_platform_thread_unlock_mutex(&globalLock); 5659 } 5660#endif 5661 return result; 5662} 5663 5664VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle(VkDevice device) { 5665 VkBool32 skip_call = VK_FALSE; 5666 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5667 loader_platform_thread_lock_mutex(&globalLock); 5668 for (auto queue : dev_data->queues) { 5669 decrementResources(dev_data, queue); 5670 if (dev_data->queueMap.find(queue) != dev_data->queueMap.end()) { 5671 // Clear all of the queue inFlightCmdBuffers (global set cleared below) 5672 dev_data->queueMap[queue].inFlightCmdBuffers.clear(); 5673 } 5674 } 5675 for (auto cmdBuffer : dev_data->globalInFlightCmdBuffers) { 5676 skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); 5677 } 5678 dev_data->globalInFlightCmdBuffers.clear(); 5679 loader_platform_thread_unlock_mutex(&globalLock); 5680 if (VK_FALSE != skip_call) 5681 return VK_ERROR_VALIDATION_FAILED_EXT; 5682 VkResult result = dev_data->device_dispatch_table->DeviceWaitIdle(device); 5683#if MTMERGE 5684 if (VK_SUCCESS == result) { 5685 loader_platform_thread_lock_mutex(&globalLock); 5686 retire_device_fences(dev_data, device); 5687 loader_platform_thread_unlock_mutex(&globalLock); 5688 } 5689#endif 5690 return result; 5691} 5692 5693VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) { 5694 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5695 bool skipCall = false; 5696 loader_platform_thread_lock_mutex(&globalLock); 5697 if (dev_data->fenceMap[fence].in_use.load()) { 5698 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 5699 (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", 5700 "Fence %#" PRIx64 " is in use by a command buffer.", (uint64_t)(fence)); 5701 } 5702#if MTMERGE 5703 delete_fence_info(dev_data, fence); 5704 auto item = dev_data->fenceMap.find(fence); 5705 if (item != dev_data->fenceMap.end()) { 5706 dev_data->fenceMap.erase(item); 5707 } 5708#endif 5709 loader_platform_thread_unlock_mutex(&globalLock); 5710 if (!skipCall) 5711 dev_data->device_dispatch_table->DestroyFence(device, fence, pAllocator); 5712} 5713 5714VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5715vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) { 5716 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5717 dev_data->device_dispatch_table->DestroySemaphore(device, semaphore, pAllocator); 5718 loader_platform_thread_lock_mutex(&globalLock); 5719 auto item = dev_data->semaphoreMap.find(semaphore); 5720 if (item != dev_data->semaphoreMap.end()) { 5721 if (item->second.in_use.load()) { 5722 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, 5723 reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS", 5724 "Cannot delete semaphore %" PRIx64 " which is in use.", reinterpret_cast<uint64_t &>(semaphore)); 5725 } 5726 dev_data->semaphoreMap.erase(semaphore); 5727 } 5728 loader_platform_thread_unlock_mutex(&globalLock); 5729 // TODO : Clean up any internal data structures using this obj. 5730} 5731 5732VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) { 5733 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5734 bool skip_call = false; 5735 loader_platform_thread_lock_mutex(&globalLock); 5736 auto event_data = dev_data->eventMap.find(event); 5737 if (event_data != dev_data->eventMap.end()) { 5738 if (event_data->second.in_use.load()) { 5739 skip_call |= log_msg( 5740 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 5741 reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS", 5742 "Cannot delete event %" PRIx64 " which is in use by a command buffer.", reinterpret_cast<uint64_t &>(event)); 5743 } 5744 dev_data->eventMap.erase(event_data); 5745 } 5746 loader_platform_thread_unlock_mutex(&globalLock); 5747 if (!skip_call) 5748 dev_data->device_dispatch_table->DestroyEvent(device, event, pAllocator); 5749 // TODO : Clean up any internal data structures using this obj. 5750} 5751 5752VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5753vkDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) { 5754 get_my_data_ptr(get_dispatch_key(device), layer_data_map) 5755 ->device_dispatch_table->DestroyQueryPool(device, queryPool, pAllocator); 5756 // TODO : Clean up any internal data structures using this obj. 5757} 5758 5759VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, 5760 uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride, 5761 VkQueryResultFlags flags) { 5762 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5763 unordered_map<QueryObject, vector<VkCommandBuffer>> queriesInFlight; 5764 GLOBAL_CB_NODE *pCB = nullptr; 5765 loader_platform_thread_lock_mutex(&globalLock); 5766 for (auto cmdBuffer : dev_data->globalInFlightCmdBuffers) { 5767 pCB = getCBNode(dev_data, cmdBuffer); 5768 for (auto queryStatePair : pCB->queryToStateMap) { 5769 queriesInFlight[queryStatePair.first].push_back(cmdBuffer); 5770 } 5771 } 5772 VkBool32 skip_call = VK_FALSE; 5773 for (uint32_t i = 0; i < queryCount; ++i) { 5774 QueryObject query = {queryPool, firstQuery + i}; 5775 auto queryElement = queriesInFlight.find(query); 5776 auto queryToStateElement = dev_data->queryToStateMap.find(query); 5777 if (queryToStateElement != dev_data->queryToStateMap.end()) { 5778 } 5779 // Available and in flight 5780 if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() && 5781 queryToStateElement->second) { 5782 for (auto cmdBuffer : queryElement->second) { 5783 pCB = getCBNode(dev_data, cmdBuffer); 5784 auto queryEventElement = pCB->waitedEventsBeforeQueryReset.find(query); 5785 if (queryEventElement == pCB->waitedEventsBeforeQueryReset.end()) { 5786 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5787 VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", 5788 "Cannot get query results on queryPool %" PRIu64 " with index %d which is in flight.", 5789 (uint64_t)(queryPool), firstQuery + i); 5790 } else { 5791 for (auto event : queryEventElement->second) { 5792 dev_data->eventMap[event].needsSignaled = true; 5793 } 5794 } 5795 } 5796 // Unavailable and in flight 5797 } else if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() && 5798 !queryToStateElement->second) { 5799 // TODO : Can there be the same query in use by multiple command buffers in flight? 5800 bool make_available = false; 5801 for (auto cmdBuffer : queryElement->second) { 5802 pCB = getCBNode(dev_data, cmdBuffer); 5803 make_available |= pCB->queryToStateMap[query]; 5804 } 5805 if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) { 5806 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 5807 VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", 5808 "Cannot get query results on queryPool %" PRIu64 " with index %d which is unavailable.", 5809 (uint64_t)(queryPool), firstQuery + i); 5810 } 5811 // Unavailable 5812 } else if (queryToStateElement != dev_data->queryToStateMap.end() && !queryToStateElement->second) { 5813 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 5814 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", 5815 "Cannot get query results on queryPool %" PRIu64 " with index %d which is unavailable.", 5816 (uint64_t)(queryPool), firstQuery + i); 5817 // Unitialized 5818 } else if (queryToStateElement == dev_data->queryToStateMap.end()) { 5819 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 5820 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", 5821 "Cannot get query results on queryPool %" PRIu64 " with index %d which is uninitialized.", 5822 (uint64_t)(queryPool), firstQuery + i); 5823 } 5824 } 5825 loader_platform_thread_unlock_mutex(&globalLock); 5826 if (skip_call) 5827 return VK_ERROR_VALIDATION_FAILED_EXT; 5828 return dev_data->device_dispatch_table->GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, 5829 flags); 5830} 5831 5832VkBool32 validateIdleBuffer(const layer_data *my_data, VkBuffer buffer) { 5833 VkBool32 skip_call = VK_FALSE; 5834 auto buffer_data = my_data->bufferMap.find(buffer); 5835 if (buffer_data == my_data->bufferMap.end()) { 5836 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, 5837 (uint64_t)(buffer), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS", 5838 "Cannot free buffer %" PRIxLEAST64 " that has not been allocated.", (uint64_t)(buffer)); 5839 } else { 5840 if (buffer_data->second.in_use.load()) { 5841 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, 5842 (uint64_t)(buffer), __LINE__, DRAWSTATE_OBJECT_INUSE, "DS", 5843 "Cannot free buffer %" PRIxLEAST64 " that is in use by a command buffer.", (uint64_t)(buffer)); 5844 } 5845 } 5846 return skip_call; 5847} 5848 5849VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5850vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) { 5851 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5852 VkBool32 skipCall = VK_FALSE; 5853 loader_platform_thread_lock_mutex(&globalLock); 5854#if MTMERGE 5855 auto item = dev_data->bufferBindingMap.find((uint64_t)buffer); 5856 if (item != dev_data->bufferBindingMap.end()) { 5857 skipCall = clear_object_binding(dev_data, device, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT); 5858 dev_data->bufferBindingMap.erase(item); 5859 } 5860#endif 5861 if (!validateIdleBuffer(dev_data, buffer) && (VK_FALSE == skipCall)) { 5862 loader_platform_thread_unlock_mutex(&globalLock); 5863 dev_data->device_dispatch_table->DestroyBuffer(device, buffer, pAllocator); 5864 loader_platform_thread_lock_mutex(&globalLock); 5865 } 5866 dev_data->bufferMap.erase(buffer); 5867 loader_platform_thread_unlock_mutex(&globalLock); 5868} 5869 5870VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5871vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) { 5872 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5873 dev_data->device_dispatch_table->DestroyBufferView(device, bufferView, pAllocator); 5874 loader_platform_thread_lock_mutex(&globalLock); 5875 auto item = dev_data->bufferViewMap.find(bufferView); 5876 if (item != dev_data->bufferViewMap.end()) { 5877 dev_data->bufferViewMap.erase(item); 5878 } 5879 loader_platform_thread_unlock_mutex(&globalLock); 5880} 5881 5882VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) { 5883 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5884 VkBool32 skipCall = VK_FALSE; 5885#if MTMERGE 5886 loader_platform_thread_lock_mutex(&globalLock); 5887 auto item = dev_data->imageBindingMap.find((uint64_t)image); 5888 if (item != dev_data->imageBindingMap.end()) { 5889 skipCall = clear_object_binding(dev_data, device, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); 5890 dev_data->imageBindingMap.erase(item); 5891 } 5892 loader_platform_thread_unlock_mutex(&globalLock); 5893#endif 5894 if (VK_FALSE == skipCall) 5895 dev_data->device_dispatch_table->DestroyImage(device, image, pAllocator); 5896 5897 loader_platform_thread_lock_mutex(&globalLock); 5898 const auto& entry = dev_data->imageMap.find(image); 5899 if (entry != dev_data->imageMap.end()) { 5900 // Clear any memory mapping for this image 5901 const auto &mem_entry = dev_data->memObjMap.find(entry->second.mem); 5902 if (mem_entry != dev_data->memObjMap.end()) 5903 mem_entry->second.image = VK_NULL_HANDLE; 5904 5905 // Remove image from imageMap 5906 dev_data->imageMap.erase(entry); 5907 } 5908 const auto& subEntry = dev_data->imageSubresourceMap.find(image); 5909 if (subEntry != dev_data->imageSubresourceMap.end()) { 5910 for (const auto& pair : subEntry->second) { 5911 dev_data->imageLayoutMap.erase(pair); 5912 } 5913 dev_data->imageSubresourceMap.erase(subEntry); 5914 } 5915 loader_platform_thread_unlock_mutex(&globalLock); 5916} 5917#if MTMERGE 5918VkBool32 print_memory_range_error(layer_data *dev_data, const uint64_t object_handle, const uint64_t other_handle, 5919 VkDebugReportObjectTypeEXT object_type) { 5920 if (object_type == VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT) { 5921 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0, 5922 MEMTRACK_INVALID_ALIASING, "MEM", "Buffer %" PRIx64 " is alised with image %" PRIx64, object_handle, 5923 other_handle); 5924 } else { 5925 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0, 5926 MEMTRACK_INVALID_ALIASING, "MEM", "Image %" PRIx64 " is alised with buffer %" PRIx64, object_handle, 5927 other_handle); 5928 } 5929} 5930 5931VkBool32 validate_memory_range(layer_data *dev_data, const vector<MEMORY_RANGE> &ranges, const MEMORY_RANGE &new_range, 5932 VkDebugReportObjectTypeEXT object_type) { 5933 VkBool32 skip_call = false; 5934 5935 for (auto range : ranges) { 5936 if ((range.end & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1)) < 5937 (new_range.start & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1))) 5938 continue; 5939 if ((range.start & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1)) > 5940 (new_range.end & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1))) 5941 continue; 5942 skip_call |= print_memory_range_error(dev_data, new_range.handle, range.handle, object_type); 5943 } 5944 return skip_call; 5945} 5946 5947VkBool32 validate_buffer_image_aliasing(layer_data *dev_data, uint64_t handle, VkDeviceMemory mem, VkDeviceSize memoryOffset, 5948 VkMemoryRequirements memRequirements, vector<MEMORY_RANGE> &ranges, 5949 const vector<MEMORY_RANGE> &other_ranges, VkDebugReportObjectTypeEXT object_type) { 5950 MEMORY_RANGE range; 5951 range.handle = handle; 5952 range.memory = mem; 5953 range.start = memoryOffset; 5954 range.end = memoryOffset + memRequirements.size - 1; 5955 ranges.push_back(range); 5956 return validate_memory_range(dev_data, other_ranges, range, object_type); 5957} 5958 5959VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 5960vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) { 5961 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5962 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 5963 loader_platform_thread_lock_mutex(&globalLock); 5964 // Track objects tied to memory 5965 uint64_t buffer_handle = (uint64_t)(buffer); 5966 VkBool32 skipCall = 5967 set_mem_binding(dev_data, device, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory"); 5968 add_object_binding_info(dev_data, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, mem); 5969 { 5970 VkMemoryRequirements memRequirements; 5971 // MTMTODO : Shouldn't this call down the chain? 5972 vkGetBufferMemoryRequirements(device, buffer, &memRequirements); 5973 skipCall |= validate_buffer_image_aliasing(dev_data, buffer_handle, mem, memoryOffset, memRequirements, 5974 dev_data->memObjMap[mem].bufferRanges, dev_data->memObjMap[mem].imageRanges, 5975 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT); 5976 } 5977 print_mem_list(dev_data, device); 5978 loader_platform_thread_unlock_mutex(&globalLock); 5979 if (VK_FALSE == skipCall) { 5980 result = dev_data->device_dispatch_table->BindBufferMemory(device, buffer, mem, memoryOffset); 5981 } 5982 return result; 5983} 5984 5985VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5986vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) { 5987 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5988 // TODO : What to track here? 5989 // Could potentially save returned mem requirements and validate values passed into BindBufferMemory 5990 my_data->device_dispatch_table->GetBufferMemoryRequirements(device, buffer, pMemoryRequirements); 5991} 5992 5993VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 5994vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) { 5995 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 5996 // TODO : What to track here? 5997 // Could potentially save returned mem requirements and validate values passed into BindImageMemory 5998 my_data->device_dispatch_table->GetImageMemoryRequirements(device, image, pMemoryRequirements); 5999} 6000#endif 6001VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6002vkDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) { 6003 get_my_data_ptr(get_dispatch_key(device), layer_data_map) 6004 ->device_dispatch_table->DestroyImageView(device, imageView, pAllocator); 6005 // TODO : Clean up any internal data structures using this obj. 6006} 6007 6008VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6009vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator) { 6010 get_my_data_ptr(get_dispatch_key(device), layer_data_map) 6011 ->device_dispatch_table->DestroyShaderModule(device, shaderModule, pAllocator); 6012 // TODO : Clean up any internal data structures using this obj. 6013} 6014 6015VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6016vkDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) { 6017 get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroyPipeline(device, pipeline, pAllocator); 6018 // TODO : Clean up any internal data structures using this obj. 6019} 6020 6021VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6022vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator) { 6023 get_my_data_ptr(get_dispatch_key(device), layer_data_map) 6024 ->device_dispatch_table->DestroyPipelineLayout(device, pipelineLayout, pAllocator); 6025 // TODO : Clean up any internal data structures using this obj. 6026} 6027 6028VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6029vkDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) { 6030 get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroySampler(device, sampler, pAllocator); 6031 // TODO : Clean up any internal data structures using this obj. 6032} 6033 6034VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6035vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator) { 6036 get_my_data_ptr(get_dispatch_key(device), layer_data_map) 6037 ->device_dispatch_table->DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator); 6038 // TODO : Clean up any internal data structures using this obj. 6039} 6040 6041VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6042vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) { 6043 get_my_data_ptr(get_dispatch_key(device), layer_data_map) 6044 ->device_dispatch_table->DestroyDescriptorPool(device, descriptorPool, pAllocator); 6045 // TODO : Clean up any internal data structures using this obj. 6046} 6047 6048VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6049vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) { 6050 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6051 6052 bool skip_call = false; 6053 loader_platform_thread_lock_mutex(&globalLock); 6054 for (uint32_t i = 0; i < commandBufferCount; i++) { 6055#if MTMERGE 6056 skip_call |= delete_cmd_buf_info(dev_data, commandPool, pCommandBuffers[i]); 6057#endif 6058 if (dev_data->globalInFlightCmdBuffers.count(pCommandBuffers[i])) { 6059 skip_call |= 6060 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6061 reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", 6062 "Attempt to free command buffer (%#" PRIxLEAST64 ") which is in use.", 6063 reinterpret_cast<uint64_t>(pCommandBuffers[i])); 6064 } 6065 // Delete CB information structure, and remove from commandBufferMap 6066 auto cb = dev_data->commandBufferMap.find(pCommandBuffers[i]); 6067 if (cb != dev_data->commandBufferMap.end()) { 6068 // reset prior to delete for data clean-up 6069 resetCB(dev_data, (*cb).second->commandBuffer); 6070 delete (*cb).second; 6071 dev_data->commandBufferMap.erase(cb); 6072 } 6073 6074 // Remove commandBuffer reference from commandPoolMap 6075 dev_data->commandPoolMap[commandPool].commandBuffers.remove(pCommandBuffers[i]); 6076 } 6077#if MTMERGE 6078 printCBList(dev_data, device); 6079#endif 6080 loader_platform_thread_unlock_mutex(&globalLock); 6081 6082 if (!skip_call) 6083 dev_data->device_dispatch_table->FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers); 6084} 6085 6086VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo, 6087 const VkAllocationCallbacks *pAllocator, 6088 VkCommandPool *pCommandPool) { 6089 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6090 6091 VkResult result = dev_data->device_dispatch_table->CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool); 6092 6093 if (VK_SUCCESS == result) { 6094 loader_platform_thread_lock_mutex(&globalLock); 6095 dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags; 6096 dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex; 6097 loader_platform_thread_unlock_mutex(&globalLock); 6098 } 6099 return result; 6100} 6101 6102VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo, 6103 const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) { 6104 6105 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6106 VkResult result = dev_data->device_dispatch_table->CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool); 6107 if (result == VK_SUCCESS) { 6108 loader_platform_thread_lock_mutex(&globalLock); 6109 dev_data->queryPoolMap[*pQueryPool].createInfo = *pCreateInfo; 6110 loader_platform_thread_unlock_mutex(&globalLock); 6111 } 6112 return result; 6113} 6114 6115VkBool32 validateCommandBuffersNotInUse(const layer_data *dev_data, VkCommandPool commandPool) { 6116 VkBool32 skipCall = VK_FALSE; 6117 auto pool_data = dev_data->commandPoolMap.find(commandPool); 6118 if (pool_data != dev_data->commandPoolMap.end()) { 6119 for (auto cmdBuffer : pool_data->second.commandBuffers) { 6120 if (dev_data->globalInFlightCmdBuffers.count(cmdBuffer)) { 6121 skipCall |= 6122 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT, 6123 (uint64_t)(commandPool), __LINE__, DRAWSTATE_OBJECT_INUSE, "DS", 6124 "Cannot reset command pool %" PRIx64 " when allocated command buffer %" PRIx64 " is in use.", 6125 (uint64_t)(commandPool), (uint64_t)(cmdBuffer)); 6126 } 6127 } 6128 } 6129 return skipCall; 6130} 6131 6132// Destroy commandPool along with all of the commandBuffers allocated from that pool 6133VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6134vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) { 6135 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6136 bool commandBufferComplete = false; 6137 bool skipCall = false; 6138 loader_platform_thread_lock_mutex(&globalLock); 6139#if MTMERGE 6140 // Verify that command buffers in pool are complete (not in-flight) 6141 // MTMTODO : Merge this with code below (separate *NotInUse() call) 6142 for (auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); 6143 it != dev_data->commandPoolMap[commandPool].commandBuffers.end(); it++) { 6144 commandBufferComplete = VK_FALSE; 6145 skipCall = checkCBCompleted(dev_data, *it, &commandBufferComplete); 6146 if (VK_FALSE == commandBufferComplete) { 6147 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6148 (uint64_t)(*it), __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", 6149 "Destroying Command Pool 0x%" PRIxLEAST64 " before " 6150 "its command buffer (0x%" PRIxLEAST64 ") has completed.", 6151 (uint64_t)(commandPool), reinterpret_cast<uint64_t>(*it)); 6152 } 6153 } 6154#endif 6155 // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandPoolMap 6156 if (dev_data->commandPoolMap.find(commandPool) != dev_data->commandPoolMap.end()) { 6157 for (auto poolCb = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); 6158 poolCb != dev_data->commandPoolMap[commandPool].commandBuffers.end();) { 6159 auto del_cb = dev_data->commandBufferMap.find(*poolCb); 6160 delete (*del_cb).second; // delete CB info structure 6161 dev_data->commandBufferMap.erase(del_cb); // Remove this command buffer from cbMap 6162 poolCb = dev_data->commandPoolMap[commandPool].commandBuffers.erase( 6163 poolCb); // Remove CB reference from commandPoolMap's list 6164 } 6165 } 6166 dev_data->commandPoolMap.erase(commandPool); 6167 6168 loader_platform_thread_unlock_mutex(&globalLock); 6169 6170 if (VK_TRUE == validateCommandBuffersNotInUse(dev_data, commandPool)) 6171 return; 6172 6173 if (!skipCall) 6174 dev_data->device_dispatch_table->DestroyCommandPool(device, commandPool, pAllocator); 6175#if MTMERGE 6176 loader_platform_thread_lock_mutex(&globalLock); 6177 auto item = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); 6178 // Remove command buffers from command buffer map 6179 while (item != dev_data->commandPoolMap[commandPool].commandBuffers.end()) { 6180 auto del_item = item++; 6181 delete_cmd_buf_info(dev_data, commandPool, *del_item); 6182 } 6183 dev_data->commandPoolMap.erase(commandPool); 6184 loader_platform_thread_unlock_mutex(&globalLock); 6185#endif 6186} 6187 6188VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6189vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) { 6190 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6191 bool commandBufferComplete = false; 6192 bool skipCall = false; 6193 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 6194#if MTMERGE 6195 // MTMTODO : Merge this with *NotInUse() call below 6196 loader_platform_thread_lock_mutex(&globalLock); 6197 auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); 6198 // Verify that CB's in pool are complete (not in-flight) 6199 while (it != dev_data->commandPoolMap[commandPool].commandBuffers.end()) { 6200 skipCall = checkCBCompleted(dev_data, (*it), &commandBufferComplete); 6201 if (!commandBufferComplete) { 6202 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6203 (uint64_t)(*it), __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", 6204 "Resetting CB %p before it has completed. You must check CB " 6205 "flag before calling vkResetCommandBuffer().", 6206 (*it)); 6207 } else { 6208 // Clear memory references at this point. 6209 skipCall |= clear_cmd_buf_and_mem_references(dev_data, (*it)); 6210 } 6211 ++it; 6212 } 6213 loader_platform_thread_unlock_mutex(&globalLock); 6214#endif 6215 if (VK_TRUE == validateCommandBuffersNotInUse(dev_data, commandPool)) 6216 return VK_ERROR_VALIDATION_FAILED_EXT; 6217 6218 if (!skipCall) 6219 result = dev_data->device_dispatch_table->ResetCommandPool(device, commandPool, flags); 6220 6221 // Reset all of the CBs allocated from this pool 6222 if (VK_SUCCESS == result) { 6223 loader_platform_thread_lock_mutex(&globalLock); 6224 auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); 6225 while (it != dev_data->commandPoolMap[commandPool].commandBuffers.end()) { 6226 resetCB(dev_data, (*it)); 6227 ++it; 6228 } 6229 loader_platform_thread_unlock_mutex(&globalLock); 6230 } 6231 return result; 6232} 6233 6234VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) { 6235 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6236 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 6237 bool skipCall = false; 6238 loader_platform_thread_lock_mutex(&globalLock); 6239 for (uint32_t i = 0; i < fenceCount; ++i) { 6240#if MTMERGE 6241 // Reset fence state in fenceCreateInfo structure 6242 // MTMTODO : Merge with code below 6243 auto fence_item = dev_data->fenceMap.find(pFences[i]); 6244 if (fence_item != dev_data->fenceMap.end()) { 6245 // Validate fences in SIGNALED state 6246 if (!(fence_item->second.createInfo.flags & VK_FENCE_CREATE_SIGNALED_BIT)) { 6247 // TODO: I don't see a Valid Usage section for ResetFences. This behavior should be documented there. 6248 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 6249 (uint64_t)pFences[i], __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", 6250 "Fence %#" PRIxLEAST64 " submitted to VkResetFences in UNSIGNALED STATE", (uint64_t)pFences[i]); 6251 } else { 6252 fence_item->second.createInfo.flags = 6253 static_cast<VkFenceCreateFlags>(fence_item->second.createInfo.flags & ~VK_FENCE_CREATE_SIGNALED_BIT); 6254 } 6255 } 6256#endif 6257 if (dev_data->fenceMap[pFences[i]].in_use.load()) { 6258 skipCall |= 6259 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, 6260 reinterpret_cast<const uint64_t &>(pFences[i]), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", 6261 "Fence %#" PRIx64 " is in use by a command buffer.", reinterpret_cast<const uint64_t &>(pFences[i])); 6262 } 6263 } 6264 loader_platform_thread_unlock_mutex(&globalLock); 6265 if (!skipCall) 6266 result = dev_data->device_dispatch_table->ResetFences(device, fenceCount, pFences); 6267 return result; 6268} 6269 6270VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6271vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) { 6272 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6273#if MTMERGE 6274 // MTMTODO : Merge with code below 6275 loader_platform_thread_lock_mutex(&globalLock); 6276 auto item = dev_data->fbMap.find(framebuffer); 6277 if (item != dev_data->fbMap.end()) { 6278 dev_data->fbMap.erase(framebuffer); 6279 } 6280 loader_platform_thread_unlock_mutex(&globalLock); 6281#endif 6282 auto fbNode = dev_data->frameBufferMap.find(framebuffer); 6283 if (fbNode != dev_data->frameBufferMap.end()) { 6284 for (auto cb : fbNode->second.referencingCmdBuffers) { 6285 auto cbNode = dev_data->commandBufferMap.find(cb); 6286 if (cbNode != dev_data->commandBufferMap.end()) { 6287 // Set CB as invalid and record destroyed framebuffer 6288 cbNode->second->state = CB_INVALID; 6289 cbNode->second->destroyedFramebuffers.insert(framebuffer); 6290 } 6291 } 6292 dev_data->frameBufferMap.erase(framebuffer); 6293 } 6294 dev_data->device_dispatch_table->DestroyFramebuffer(device, framebuffer, pAllocator); 6295} 6296 6297VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6298vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) { 6299 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6300 dev_data->device_dispatch_table->DestroyRenderPass(device, renderPass, pAllocator); 6301 loader_platform_thread_lock_mutex(&globalLock); 6302 dev_data->renderPassMap.erase(renderPass); 6303 dev_data->passMap.erase(renderPass); 6304 loader_platform_thread_unlock_mutex(&globalLock); 6305} 6306 6307VkBool32 validate_queue_family_indices(layer_data *dev_data, const char *function_name, const uint32_t count, 6308 const uint32_t *indices) { 6309 VkBool32 skipCall = VK_FALSE; 6310 for (auto i = 0; i < count; i++) { 6311 if (indices[i] >= dev_data->physDevProperties.queue_family_properties.size()) { 6312 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 6313 DRAWSTATE_INVALID_QUEUE_INDEX, "DS", 6314 "%s has QueueFamilyIndex greater than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER 6315 ") for this device.", 6316 function_name, dev_data->physDevProperties.queue_family_properties.size()); 6317 } 6318 } 6319 return skipCall; 6320} 6321 6322VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6323vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) { 6324 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 6325 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6326 bool skipCall = validate_queue_family_indices(dev_data, "vkCreateBuffer", pCreateInfo->queueFamilyIndexCount, 6327 pCreateInfo->pQueueFamilyIndices); 6328 if (!skipCall) { 6329 result = dev_data->device_dispatch_table->CreateBuffer(device, pCreateInfo, pAllocator, pBuffer); 6330 } 6331 6332 if (VK_SUCCESS == result) { 6333 loader_platform_thread_lock_mutex(&globalLock); 6334#if MTMERGE 6335 add_object_create_info(dev_data, (uint64_t)*pBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, pCreateInfo); 6336#endif 6337 // TODO : This doesn't create deep copy of pQueueFamilyIndices so need to fix that if/when we want that data to be valid 6338 dev_data->bufferMap[*pBuffer].create_info = unique_ptr<VkBufferCreateInfo>(new VkBufferCreateInfo(*pCreateInfo)); 6339 dev_data->bufferMap[*pBuffer].in_use.store(0); 6340 loader_platform_thread_unlock_mutex(&globalLock); 6341 } 6342 return result; 6343} 6344 6345VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo, 6346 const VkAllocationCallbacks *pAllocator, VkBufferView *pView) { 6347 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6348 VkResult result = dev_data->device_dispatch_table->CreateBufferView(device, pCreateInfo, pAllocator, pView); 6349 if (VK_SUCCESS == result) { 6350 loader_platform_thread_lock_mutex(&globalLock); 6351 dev_data->bufferViewMap[*pView] = VkBufferViewCreateInfo(*pCreateInfo); 6352#if MTMERGE 6353 // In order to create a valid buffer view, the buffer must have been created with at least one of the 6354 // following flags: UNIFORM_TEXEL_BUFFER_BIT or STORAGE_TEXEL_BUFFER_BIT 6355 validate_buffer_usage_flags(dev_data, device, pCreateInfo->buffer, 6356 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, VK_FALSE, 6357 "vkCreateBufferView()", "VK_BUFFER_USAGE_[STORAGE|UNIFORM]_TEXEL_BUFFER_BIT"); 6358#endif 6359 loader_platform_thread_unlock_mutex(&globalLock); 6360 } 6361 return result; 6362} 6363 6364VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6365vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage) { 6366 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 6367 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6368 bool skipCall = validate_queue_family_indices(dev_data, "vkCreateImage", pCreateInfo->queueFamilyIndexCount, 6369 pCreateInfo->pQueueFamilyIndices); 6370 if (!skipCall) { 6371 result = dev_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage); 6372 } 6373 6374 if (VK_SUCCESS == result) { 6375 loader_platform_thread_lock_mutex(&globalLock); 6376#if MTMERGE 6377 add_object_create_info(dev_data, (uint64_t)*pImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, pCreateInfo); 6378#endif 6379 IMAGE_LAYOUT_NODE image_node; 6380 image_node.layout = pCreateInfo->initialLayout; 6381 image_node.format = pCreateInfo->format; 6382 dev_data->imageMap[*pImage].createInfo = *pCreateInfo; 6383 ImageSubresourcePair subpair = {*pImage, false, VkImageSubresource()}; 6384 dev_data->imageSubresourceMap[*pImage].push_back(subpair); 6385 dev_data->imageLayoutMap[subpair] = image_node; 6386 loader_platform_thread_unlock_mutex(&globalLock); 6387 } 6388 return result; 6389} 6390 6391static void ResolveRemainingLevelsLayers(layer_data *dev_data, VkImageSubresourceRange *range, VkImage image) { 6392 /* expects globalLock to be held by caller */ 6393 6394 auto image_node_it = dev_data->imageMap.find(image); 6395 if (image_node_it != dev_data->imageMap.end()) { 6396 /* If the caller used the special values VK_REMAINING_MIP_LEVELS and 6397 * VK_REMAINING_ARRAY_LAYERS, resolve them now in our internal state to 6398 * the actual values. 6399 */ 6400 if (range->levelCount == VK_REMAINING_MIP_LEVELS) { 6401 range->levelCount = image_node_it->second.createInfo.mipLevels - range->baseMipLevel; 6402 } 6403 6404 if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) { 6405 range->layerCount = image_node_it->second.createInfo.arrayLayers - range->baseArrayLayer; 6406 } 6407 } 6408} 6409 6410// Return the correct layer/level counts if the caller used the special 6411// values VK_REMAINING_MIP_LEVELS or VK_REMAINING_ARRAY_LAYERS. 6412static void ResolveRemainingLevelsLayers(layer_data *dev_data, uint32_t *levels, uint32_t *layers, VkImageSubresourceRange range, 6413 VkImage image) { 6414 /* expects globalLock to be held by caller */ 6415 6416 *levels = range.levelCount; 6417 *layers = range.layerCount; 6418 auto image_node_it = dev_data->imageMap.find(image); 6419 if (image_node_it != dev_data->imageMap.end()) { 6420 if (range.levelCount == VK_REMAINING_MIP_LEVELS) { 6421 *levels = image_node_it->second.createInfo.mipLevels - range.baseMipLevel; 6422 } 6423 if (range.layerCount == VK_REMAINING_ARRAY_LAYERS) { 6424 *layers = image_node_it->second.createInfo.arrayLayers - range.baseArrayLayer; 6425 } 6426 } 6427} 6428 6429VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo, 6430 const VkAllocationCallbacks *pAllocator, VkImageView *pView) { 6431 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6432 VkResult result = dev_data->device_dispatch_table->CreateImageView(device, pCreateInfo, pAllocator, pView); 6433 if (VK_SUCCESS == result) { 6434 loader_platform_thread_lock_mutex(&globalLock); 6435 VkImageViewCreateInfo localCI = VkImageViewCreateInfo(*pCreateInfo); 6436 ResolveRemainingLevelsLayers(dev_data, &localCI.subresourceRange, pCreateInfo->image); 6437 dev_data->imageViewMap[*pView] = localCI; 6438#if MTMERGE 6439 // Validate that img has correct usage flags set 6440 validate_image_usage_flags(dev_data, device, pCreateInfo->image, 6441 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | 6442 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 6443 VK_FALSE, "vkCreateImageView()", "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT]_BIT"); 6444#endif 6445 loader_platform_thread_unlock_mutex(&globalLock); 6446 } 6447 return result; 6448} 6449 6450VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6451vkCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence) { 6452 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6453 VkResult result = dev_data->device_dispatch_table->CreateFence(device, pCreateInfo, pAllocator, pFence); 6454 if (VK_SUCCESS == result) { 6455 loader_platform_thread_lock_mutex(&globalLock); 6456 FENCE_NODE *pFN = &dev_data->fenceMap[*pFence]; 6457#if MTMERGE 6458 memset(pFN, 0, sizeof(MT_FENCE_INFO)); 6459 memcpy(&(pFN->createInfo), pCreateInfo, sizeof(VkFenceCreateInfo)); 6460 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) { 6461 pFN->firstTimeFlag = VK_TRUE; 6462 } 6463#endif 6464 pFN->in_use.store(0); 6465 loader_platform_thread_unlock_mutex(&globalLock); 6466 } 6467 return result; 6468} 6469 6470// TODO handle pipeline caches 6471VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo, 6472 const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) { 6473 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6474 VkResult result = dev_data->device_dispatch_table->CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache); 6475 return result; 6476} 6477 6478VKAPI_ATTR void VKAPI_CALL 6479vkDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks *pAllocator) { 6480 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6481 dev_data->device_dispatch_table->DestroyPipelineCache(device, pipelineCache, pAllocator); 6482} 6483 6484VKAPI_ATTR VkResult VKAPI_CALL 6485vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize, void *pData) { 6486 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6487 VkResult result = dev_data->device_dispatch_table->GetPipelineCacheData(device, pipelineCache, pDataSize, pData); 6488 return result; 6489} 6490 6491VKAPI_ATTR VkResult VKAPI_CALL 6492vkMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches) { 6493 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6494 VkResult result = dev_data->device_dispatch_table->MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches); 6495 return result; 6496} 6497 6498VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6499vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count, 6500 const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, 6501 VkPipeline *pPipelines) { 6502 VkResult result = VK_SUCCESS; 6503 // TODO What to do with pipelineCache? 6504 // The order of operations here is a little convoluted but gets the job done 6505 // 1. Pipeline create state is first shadowed into PIPELINE_NODE struct 6506 // 2. Create state is then validated (which uses flags setup during shadowing) 6507 // 3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap 6508 VkBool32 skipCall = VK_FALSE; 6509 // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic 6510 vector<PIPELINE_NODE *> pPipeNode(count); 6511 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6512 6513 uint32_t i = 0; 6514 loader_platform_thread_lock_mutex(&globalLock); 6515 6516 for (i = 0; i < count; i++) { 6517 pPipeNode[i] = initGraphicsPipeline(dev_data, &pCreateInfos[i]); 6518 skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode, i); 6519 } 6520 6521 if (VK_FALSE == skipCall) { 6522 loader_platform_thread_unlock_mutex(&globalLock); 6523 result = dev_data->device_dispatch_table->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, 6524 pPipelines); 6525 loader_platform_thread_lock_mutex(&globalLock); 6526 for (i = 0; i < count; i++) { 6527 pPipeNode[i]->pipeline = pPipelines[i]; 6528 dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i]; 6529 } 6530 loader_platform_thread_unlock_mutex(&globalLock); 6531 } else { 6532 for (i = 0; i < count; i++) { 6533 if (pPipeNode[i]) { 6534 // If we allocated a pipeNode, need to clean it up here 6535 delete[] pPipeNode[i]->pVertexBindingDescriptions; 6536 delete[] pPipeNode[i]->pVertexAttributeDescriptions; 6537 delete[] pPipeNode[i]->pAttachments; 6538 delete pPipeNode[i]; 6539 } 6540 } 6541 loader_platform_thread_unlock_mutex(&globalLock); 6542 return VK_ERROR_VALIDATION_FAILED_EXT; 6543 } 6544 return result; 6545} 6546 6547VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6548vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count, 6549 const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, 6550 VkPipeline *pPipelines) { 6551 VkResult result = VK_SUCCESS; 6552 VkBool32 skipCall = VK_FALSE; 6553 6554 // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic 6555 vector<PIPELINE_NODE *> pPipeNode(count); 6556 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6557 6558 uint32_t i = 0; 6559 loader_platform_thread_lock_mutex(&globalLock); 6560 for (i = 0; i < count; i++) { 6561 // TODO: Verify compute stage bits 6562 6563 // Create and initialize internal tracking data structure 6564 pPipeNode[i] = new PIPELINE_NODE; 6565 memcpy(&pPipeNode[i]->computePipelineCI, (const void *)&pCreateInfos[i], sizeof(VkComputePipelineCreateInfo)); 6566 6567 // TODO: Add Compute Pipeline Verification 6568 // skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode[i]); 6569 } 6570 6571 if (VK_FALSE == skipCall) { 6572 loader_platform_thread_unlock_mutex(&globalLock); 6573 result = dev_data->device_dispatch_table->CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, 6574 pPipelines); 6575 loader_platform_thread_lock_mutex(&globalLock); 6576 for (i = 0; i < count; i++) { 6577 pPipeNode[i]->pipeline = pPipelines[i]; 6578 dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i]; 6579 } 6580 loader_platform_thread_unlock_mutex(&globalLock); 6581 } else { 6582 for (i = 0; i < count; i++) { 6583 // Clean up any locally allocated data structures 6584 delete pPipeNode[i]; 6585 } 6586 loader_platform_thread_unlock_mutex(&globalLock); 6587 return VK_ERROR_VALIDATION_FAILED_EXT; 6588 } 6589 return result; 6590} 6591 6592VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo, 6593 const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) { 6594 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6595 VkResult result = dev_data->device_dispatch_table->CreateSampler(device, pCreateInfo, pAllocator, pSampler); 6596 if (VK_SUCCESS == result) { 6597 loader_platform_thread_lock_mutex(&globalLock); 6598 dev_data->sampleMap[*pSampler] = unique_ptr<SAMPLER_NODE>(new SAMPLER_NODE(pSampler, pCreateInfo)); 6599 loader_platform_thread_unlock_mutex(&globalLock); 6600 } 6601 return result; 6602} 6603 6604VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6605vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, 6606 const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) { 6607 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6608 VkResult result = dev_data->device_dispatch_table->CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout); 6609 if (VK_SUCCESS == result) { 6610 // TODOSC : Capture layout bindings set 6611 LAYOUT_NODE *pNewNode = new LAYOUT_NODE; 6612 if (NULL == pNewNode) { 6613 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, 6614 (uint64_t)*pSetLayout, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", 6615 "Out of memory while attempting to allocate LAYOUT_NODE in vkCreateDescriptorSetLayout()")) 6616 return VK_ERROR_VALIDATION_FAILED_EXT; 6617 } 6618 memcpy((void *)&pNewNode->createInfo, pCreateInfo, sizeof(VkDescriptorSetLayoutCreateInfo)); 6619 pNewNode->createInfo.pBindings = new VkDescriptorSetLayoutBinding[pCreateInfo->bindingCount]; 6620 memcpy((void *)pNewNode->createInfo.pBindings, pCreateInfo->pBindings, 6621 sizeof(VkDescriptorSetLayoutBinding) * pCreateInfo->bindingCount); 6622 // g++ does not like reserve with size 0 6623 if (pCreateInfo->bindingCount) 6624 pNewNode->bindingToIndexMap.reserve(pCreateInfo->bindingCount); 6625 uint32_t totalCount = 0; 6626 for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) { 6627 if (!pNewNode->bindingToIndexMap.emplace(pCreateInfo->pBindings[i].binding, i).second) { 6628 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 6629 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)*pSetLayout, __LINE__, 6630 DRAWSTATE_INVALID_LAYOUT, "DS", "duplicated binding number in " 6631 "VkDescriptorSetLayoutBinding")) 6632 return VK_ERROR_VALIDATION_FAILED_EXT; 6633 } else { 6634 pNewNode->bindingToIndexMap[pCreateInfo->pBindings[i].binding] = i; 6635 } 6636 totalCount += pCreateInfo->pBindings[i].descriptorCount; 6637 if (pCreateInfo->pBindings[i].pImmutableSamplers) { 6638 VkSampler **ppIS = (VkSampler **)&pNewNode->createInfo.pBindings[i].pImmutableSamplers; 6639 *ppIS = new VkSampler[pCreateInfo->pBindings[i].descriptorCount]; 6640 memcpy(*ppIS, pCreateInfo->pBindings[i].pImmutableSamplers, 6641 pCreateInfo->pBindings[i].descriptorCount * sizeof(VkSampler)); 6642 } 6643 } 6644 pNewNode->layout = *pSetLayout; 6645 pNewNode->startIndex = 0; 6646 if (totalCount > 0) { 6647 pNewNode->descriptorTypes.resize(totalCount); 6648 pNewNode->stageFlags.resize(totalCount); 6649 uint32_t offset = 0; 6650 uint32_t j = 0; 6651 VkDescriptorType dType; 6652 for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) { 6653 dType = pCreateInfo->pBindings[i].descriptorType; 6654 for (j = 0; j < pCreateInfo->pBindings[i].descriptorCount; j++) { 6655 pNewNode->descriptorTypes[offset + j] = dType; 6656 pNewNode->stageFlags[offset + j] = pCreateInfo->pBindings[i].stageFlags; 6657 if ((dType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) || 6658 (dType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) { 6659 pNewNode->dynamicDescriptorCount++; 6660 } 6661 } 6662 offset += j; 6663 } 6664 pNewNode->endIndex = pNewNode->startIndex + totalCount - 1; 6665 } else { // no descriptors 6666 pNewNode->endIndex = 0; 6667 } 6668 // Put new node at Head of global Layer list 6669 loader_platform_thread_lock_mutex(&globalLock); 6670 dev_data->descriptorSetLayoutMap[*pSetLayout] = pNewNode; 6671 loader_platform_thread_unlock_mutex(&globalLock); 6672 } 6673 return result; 6674} 6675 6676static bool validatePushConstantSize(const layer_data *dev_data, const uint32_t offset, const uint32_t size, 6677 const char *caller_name) { 6678 bool skipCall = false; 6679 if ((offset + size) > dev_data->physDevProperties.properties.limits.maxPushConstantsSize) { 6680 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 6681 DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "%s call has push constants with offset %u and size %u that " 6682 "exceeds this device's maxPushConstantSize of %u.", 6683 caller_name, offset, size, dev_data->physDevProperties.properties.limits.maxPushConstantsSize); 6684 } 6685 return skipCall; 6686} 6687 6688VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, 6689 const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) { 6690 bool skipCall = false; 6691 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6692 uint32_t i = 0; 6693 for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) { 6694 skipCall |= validatePushConstantSize(dev_data, pCreateInfo->pPushConstantRanges[i].offset, 6695 pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()"); 6696 if ((pCreateInfo->pPushConstantRanges[i].size == 0) || ((pCreateInfo->pPushConstantRanges[i].size & 0x3) != 0)) { 6697 skipCall |= 6698 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 6699 DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "vkCreatePipelineLayout() call has push constant index %u with " 6700 "size %u. Size must be greater than zero and a multiple of 4.", 6701 i, pCreateInfo->pPushConstantRanges[i].size); 6702 } 6703 // TODO : Add warning if ranges overlap 6704 } 6705 VkResult result = dev_data->device_dispatch_table->CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout); 6706 if (VK_SUCCESS == result) { 6707 loader_platform_thread_lock_mutex(&globalLock); 6708 // TODOSC : Merge capture of the setLayouts per pipeline 6709 PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout]; 6710 plNode.descriptorSetLayouts.resize(pCreateInfo->setLayoutCount); 6711 for (i = 0; i < pCreateInfo->setLayoutCount; ++i) { 6712 plNode.descriptorSetLayouts[i] = pCreateInfo->pSetLayouts[i]; 6713 } 6714 plNode.pushConstantRanges.resize(pCreateInfo->pushConstantRangeCount); 6715 for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) { 6716 plNode.pushConstantRanges[i] = pCreateInfo->pPushConstantRanges[i]; 6717 } 6718 loader_platform_thread_unlock_mutex(&globalLock); 6719 } 6720 return result; 6721} 6722 6723VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6724vkCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, 6725 VkDescriptorPool *pDescriptorPool) { 6726 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6727 VkResult result = dev_data->device_dispatch_table->CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool); 6728 if (VK_SUCCESS == result) { 6729 // Insert this pool into Global Pool LL at head 6730 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, 6731 (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", "Created Descriptor Pool %#" PRIxLEAST64, 6732 (uint64_t)*pDescriptorPool)) 6733 return VK_ERROR_VALIDATION_FAILED_EXT; 6734 DESCRIPTOR_POOL_NODE *pNewNode = new DESCRIPTOR_POOL_NODE(*pDescriptorPool, pCreateInfo); 6735 if (NULL == pNewNode) { 6736 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, 6737 (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", 6738 "Out of memory while attempting to allocate DESCRIPTOR_POOL_NODE in vkCreateDescriptorPool()")) 6739 return VK_ERROR_VALIDATION_FAILED_EXT; 6740 } else { 6741 loader_platform_thread_lock_mutex(&globalLock); 6742 dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode; 6743 loader_platform_thread_unlock_mutex(&globalLock); 6744 } 6745 } else { 6746 // Need to do anything if pool create fails? 6747 } 6748 return result; 6749} 6750 6751VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6752vkResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) { 6753 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6754 VkResult result = dev_data->device_dispatch_table->ResetDescriptorPool(device, descriptorPool, flags); 6755 if (VK_SUCCESS == result) { 6756 loader_platform_thread_lock_mutex(&globalLock); 6757 clearDescriptorPool(dev_data, device, descriptorPool, flags); 6758 loader_platform_thread_unlock_mutex(&globalLock); 6759 } 6760 return result; 6761} 6762 6763VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6764vkAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets) { 6765 VkBool32 skipCall = VK_FALSE; 6766 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6767 6768 loader_platform_thread_lock_mutex(&globalLock); 6769 // Verify that requested descriptorSets are available in pool 6770 DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool); 6771 if (!pPoolNode) { 6772 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, 6773 (uint64_t)pAllocateInfo->descriptorPool, __LINE__, DRAWSTATE_INVALID_POOL, "DS", 6774 "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call", 6775 (uint64_t)pAllocateInfo->descriptorPool); 6776 } else { // Make sure pool has all the available descriptors before calling down chain 6777 skipCall |= validate_descriptor_availability_in_pool(dev_data, pPoolNode, pAllocateInfo->descriptorSetCount, 6778 pAllocateInfo->pSetLayouts); 6779 } 6780 loader_platform_thread_unlock_mutex(&globalLock); 6781 if (skipCall) 6782 return VK_ERROR_VALIDATION_FAILED_EXT; 6783 VkResult result = dev_data->device_dispatch_table->AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets); 6784 if (VK_SUCCESS == result) { 6785 loader_platform_thread_lock_mutex(&globalLock); 6786 DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool); 6787 if (pPoolNode) { 6788 if (pAllocateInfo->descriptorSetCount == 0) { 6789 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 6790 pAllocateInfo->descriptorSetCount, __LINE__, DRAWSTATE_NONE, "DS", 6791 "AllocateDescriptorSets called with 0 count"); 6792 } 6793 for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; i++) { 6794 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, 6795 (uint64_t)pDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS", "Created Descriptor Set %#" PRIxLEAST64, 6796 (uint64_t)pDescriptorSets[i]); 6797 // Create new set node and add to head of pool nodes 6798 SET_NODE *pNewNode = new SET_NODE; 6799 if (NULL == pNewNode) { 6800 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 6801 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, 6802 DRAWSTATE_OUT_OF_MEMORY, "DS", 6803 "Out of memory while attempting to allocate SET_NODE in vkAllocateDescriptorSets()")) 6804 return VK_ERROR_VALIDATION_FAILED_EXT; 6805 } else { 6806 // TODO : Pool should store a total count of each type of Descriptor available 6807 // When descriptors are allocated, decrement the count and validate here 6808 // that the count doesn't go below 0. One reset/free need to bump count back up. 6809 // Insert set at head of Set LL for this pool 6810 pNewNode->pNext = pPoolNode->pSets; 6811 pNewNode->in_use.store(0); 6812 pPoolNode->pSets = pNewNode; 6813 LAYOUT_NODE *pLayout = getLayoutNode(dev_data, pAllocateInfo->pSetLayouts[i]); 6814 if (NULL == pLayout) { 6815 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 6816 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pAllocateInfo->pSetLayouts[i], 6817 __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS", 6818 "Unable to find set layout node for layout %#" PRIxLEAST64 6819 " specified in vkAllocateDescriptorSets() call", 6820 (uint64_t)pAllocateInfo->pSetLayouts[i])) 6821 return VK_ERROR_VALIDATION_FAILED_EXT; 6822 } 6823 pNewNode->pLayout = pLayout; 6824 pNewNode->pool = pAllocateInfo->descriptorPool; 6825 pNewNode->set = pDescriptorSets[i]; 6826 pNewNode->descriptorCount = (pLayout->createInfo.bindingCount != 0) ? pLayout->endIndex + 1 : 0; 6827 if (pNewNode->descriptorCount) { 6828 size_t descriptorArraySize = sizeof(GENERIC_HEADER *) * pNewNode->descriptorCount; 6829 pNewNode->ppDescriptors = new GENERIC_HEADER *[descriptorArraySize]; 6830 memset(pNewNode->ppDescriptors, 0, descriptorArraySize); 6831 } 6832 dev_data->setMap[pDescriptorSets[i]] = pNewNode; 6833 } 6834 } 6835 } 6836 loader_platform_thread_unlock_mutex(&globalLock); 6837 } 6838 return result; 6839} 6840 6841VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6842vkFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count, const VkDescriptorSet *pDescriptorSets) { 6843 VkBool32 skipCall = VK_FALSE; 6844 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6845 // Make sure that no sets being destroyed are in-flight 6846 loader_platform_thread_lock_mutex(&globalLock); 6847 for (uint32_t i = 0; i < count; ++i) 6848 skipCall |= validateIdleDescriptorSet(dev_data, pDescriptorSets[i], "vkFreeDesriptorSets"); 6849 DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, descriptorPool); 6850 if (pPoolNode && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pPoolNode->createInfo.flags)) { 6851 // Can't Free from a NON_FREE pool 6852 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 6853 (uint64_t)device, __LINE__, DRAWSTATE_CANT_FREE_FROM_NON_FREE_POOL, "DS", 6854 "It is invalid to call vkFreeDescriptorSets() with a pool created without setting " 6855 "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT."); 6856 } 6857 loader_platform_thread_unlock_mutex(&globalLock); 6858 if (VK_FALSE != skipCall) 6859 return VK_ERROR_VALIDATION_FAILED_EXT; 6860 VkResult result = dev_data->device_dispatch_table->FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets); 6861 if (VK_SUCCESS == result) { 6862 // For each freed descriptor add it back into the pool as available 6863 loader_platform_thread_lock_mutex(&globalLock); 6864 for (uint32_t i = 0; i < count; ++i) { 6865 SET_NODE *pSet = dev_data->setMap[pDescriptorSets[i]]; // getSetNode() without locking 6866 invalidateBoundCmdBuffers(dev_data, pSet); 6867 LAYOUT_NODE *pLayout = pSet->pLayout; 6868 uint32_t typeIndex = 0, poolSizeCount = 0; 6869 for (uint32_t j = 0; j < pLayout->createInfo.bindingCount; ++j) { 6870 typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBindings[j].descriptorType); 6871 poolSizeCount = pLayout->createInfo.pBindings[j].descriptorCount; 6872 pPoolNode->availableDescriptorTypeCount[typeIndex] += poolSizeCount; 6873 } 6874 } 6875 loader_platform_thread_unlock_mutex(&globalLock); 6876 } 6877 // TODO : Any other clean-up or book-keeping to do here? 6878 return result; 6879} 6880 6881VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 6882vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites, 6883 uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) { 6884 // dsUpdate will return VK_TRUE only if a bailout error occurs, so we want to call down tree when update returns VK_FALSE 6885 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6886 loader_platform_thread_lock_mutex(&globalLock); 6887#if MTMERGE 6888 // MTMTODO : Merge this in with existing update code below and handle descriptor copies case 6889 uint32_t j = 0; 6890 for (uint32_t i = 0; i < descriptorWriteCount; ++i) { 6891 if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { 6892 for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) { 6893 dev_data->descriptorSetMap[pDescriptorWrites[i].dstSet].images.push_back( 6894 pDescriptorWrites[i].pImageInfo[j].imageView); 6895 } 6896 } else if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { 6897 for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) { 6898 dev_data->descriptorSetMap[pDescriptorWrites[i].dstSet].buffers.push_back( 6899 dev_data->bufferViewMap[pDescriptorWrites[i].pTexelBufferView[j]].buffer); 6900 } 6901 } else if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || 6902 pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) { 6903 for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) { 6904 dev_data->descriptorSetMap[pDescriptorWrites[i].dstSet].buffers.push_back( 6905 pDescriptorWrites[i].pBufferInfo[j].buffer); 6906 } 6907 } 6908 } 6909#endif 6910 VkBool32 rtn = dsUpdate(dev_data, device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies); 6911 loader_platform_thread_unlock_mutex(&globalLock); 6912 if (!rtn) { 6913 dev_data->device_dispatch_table->UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, 6914 pDescriptorCopies); 6915 } 6916} 6917 6918VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6919vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo, VkCommandBuffer *pCommandBuffer) { 6920 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 6921 VkResult result = dev_data->device_dispatch_table->AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer); 6922 if (VK_SUCCESS == result) { 6923 loader_platform_thread_lock_mutex(&globalLock); 6924 for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) { 6925#if MTMERGE 6926 add_cmd_buf_info(dev_data, pCreateInfo->commandPool, pCommandBuffer[i]); 6927#endif 6928 // Validate command pool 6929 if (dev_data->commandPoolMap.find(pCreateInfo->commandPool) != dev_data->commandPoolMap.end()) { 6930 // Add command buffer to its commandPool map 6931#if !MTMERGE 6932 dev_data->commandPoolMap[pCreateInfo->commandPool].commandBuffers.push_back(pCommandBuffer[i]); 6933#endif 6934 GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE; 6935 // Add command buffer to map 6936 dev_data->commandBufferMap[pCommandBuffer[i]] = pCB; 6937 resetCB(dev_data, pCommandBuffer[i]); 6938 pCB->createInfo = *pCreateInfo; 6939 pCB->device = device; 6940 } 6941 } 6942#if MTMERGE 6943 printCBList(dev_data, device); 6944#endif 6945 loader_platform_thread_unlock_mutex(&globalLock); 6946 } 6947 return result; 6948} 6949 6950VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 6951vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) { 6952 VkBool32 skipCall = VK_FALSE; 6953 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 6954 loader_platform_thread_lock_mutex(&globalLock); 6955 // Validate command buffer level 6956 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 6957 if (pCB) { 6958#if MTMERGE 6959 bool commandBufferComplete = false; 6960 // MTMTODO : Merge this with code below 6961 // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references 6962 skipCall = checkCBCompleted(dev_data, commandBuffer, &commandBufferComplete); 6963 6964 if (!commandBufferComplete) { 6965 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6966 (uint64_t)commandBuffer, __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", 6967 "Calling vkBeginCommandBuffer() on active CB %p before it has completed. " 6968 "You must check CB flag before this call.", 6969 commandBuffer); 6970 } 6971#endif 6972 if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) { 6973 // Secondary Command Buffer 6974 const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo; 6975 if (!pInfo) { 6976 skipCall |= 6977 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6978 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 6979 "vkBeginCommandBuffer(): Secondary Command Buffer (%p) must have inheritance info.", 6980 reinterpret_cast<void *>(commandBuffer)); 6981 } else { 6982 if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) { 6983 if (!pInfo->renderPass) { // renderpass should NOT be null for an Secondary CB 6984 skipCall |= log_msg( 6985 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6986 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 6987 "vkBeginCommandBuffer(): Secondary Command Buffers (%p) must specify a valid renderpass parameter.", 6988 reinterpret_cast<void *>(commandBuffer)); 6989 } 6990 if (!pInfo->framebuffer) { // framebuffer may be null for an Secondary CB, but this affects perf 6991 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, 6992 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 6993 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, 6994 "DS", "vkBeginCommandBuffer(): Secondary Command Buffers (%p) may perform better if a " 6995 "valid framebuffer parameter is specified.", 6996 reinterpret_cast<void *>(commandBuffer)); 6997 } else { 6998 string errorString = ""; 6999 auto fbNode = dev_data->frameBufferMap.find(pInfo->framebuffer); 7000 if (fbNode != dev_data->frameBufferMap.end()) { 7001 VkRenderPass fbRP = fbNode->second.createInfo.renderPass; 7002 if (!verify_renderpass_compatibility(dev_data, fbRP, pInfo->renderPass, errorString)) { 7003 // renderPass that framebuffer was created with 7004 // must 7005 // be compatible with local renderPass 7006 skipCall |= 7007 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7008 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7009 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, 7010 "DS", "vkBeginCommandBuffer(): Secondary Command " 7011 "Buffer (%p) renderPass (%#" PRIxLEAST64 ") is incompatible w/ framebuffer " 7012 "(%#" PRIxLEAST64 ") w/ render pass (%#" PRIxLEAST64 ") due to: %s", 7013 reinterpret_cast<void *>(commandBuffer), (uint64_t)(pInfo->renderPass), 7014 (uint64_t)(pInfo->framebuffer), (uint64_t)(fbRP), errorString.c_str()); 7015 } 7016 // Connect this framebuffer to this cmdBuffer 7017 fbNode->second.referencingCmdBuffers.insert(pCB->commandBuffer); 7018 } 7019 } 7020 } 7021 if ((pInfo->occlusionQueryEnable == VK_FALSE || 7022 dev_data->physDevProperties.features.occlusionQueryPrecise == VK_FALSE) && 7023 (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) { 7024 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7025 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer), 7026 __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 7027 "vkBeginCommandBuffer(): Secondary Command Buffer (%p) must not have " 7028 "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not " 7029 "support precise occlusion queries.", 7030 reinterpret_cast<void *>(commandBuffer)); 7031 } 7032 } 7033 if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) { 7034 auto rp_data = dev_data->renderPassMap.find(pInfo->renderPass); 7035 if (rp_data != dev_data->renderPassMap.end() && rp_data->second && rp_data->second->pCreateInfo) { 7036 if (pInfo->subpass >= rp_data->second->pCreateInfo->subpassCount) { 7037 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7038 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__, 7039 DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 7040 "vkBeginCommandBuffer(): Secondary Command Buffers (%p) must has a subpass index (%d) " 7041 "that is less than the number of subpasses (%d).", 7042 (void *)commandBuffer, pInfo->subpass, rp_data->second->pCreateInfo->subpassCount); 7043 } 7044 } 7045 } 7046 } 7047 if (CB_RECORDING == pCB->state) { 7048 skipCall |= 7049 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7050 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 7051 "vkBeginCommandBuffer(): Cannot call Begin on CB (%#" PRIxLEAST64 7052 ") in the RECORDING state. Must first call vkEndCommandBuffer().", 7053 (uint64_t)commandBuffer); 7054 } else if (CB_RECORDED == pCB->state) { 7055 VkCommandPool cmdPool = pCB->createInfo.commandPool; 7056 if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) { 7057 skipCall |= 7058 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7059 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", 7060 "Call to vkBeginCommandBuffer() on command buffer (%#" PRIxLEAST64 7061 ") attempts to implicitly reset cmdBuffer created from command pool (%#" PRIxLEAST64 7062 ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.", 7063 (uint64_t)commandBuffer, (uint64_t)cmdPool); 7064 } 7065 resetCB(dev_data, commandBuffer); 7066 } 7067 // Set updated state here in case implicit reset occurs above 7068 pCB->state = CB_RECORDING; 7069 pCB->beginInfo = *pBeginInfo; 7070 if (pCB->beginInfo.pInheritanceInfo) { 7071 pCB->inheritanceInfo = *(pCB->beginInfo.pInheritanceInfo); 7072 pCB->beginInfo.pInheritanceInfo = &pCB->inheritanceInfo; 7073 } 7074 } else { 7075 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7076 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 7077 "In vkBeginCommandBuffer() and unable to find CommandBuffer Node for CB %p!", (void *)commandBuffer); 7078 } 7079 loader_platform_thread_unlock_mutex(&globalLock); 7080 if (VK_FALSE != skipCall) { 7081 return VK_ERROR_VALIDATION_FAILED_EXT; 7082 } 7083 VkResult result = dev_data->device_dispatch_table->BeginCommandBuffer(commandBuffer, pBeginInfo); 7084#if MTMERGE 7085 loader_platform_thread_lock_mutex(&globalLock); 7086 clear_cmd_buf_and_mem_references(dev_data, commandBuffer); 7087 loader_platform_thread_unlock_mutex(&globalLock); 7088#endif 7089 return result; 7090} 7091 7092VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(VkCommandBuffer commandBuffer) { 7093 VkBool32 skipCall = VK_FALSE; 7094 VkResult result = VK_SUCCESS; 7095 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7096 loader_platform_thread_lock_mutex(&globalLock); 7097 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7098 if (pCB) { 7099 if (pCB->state != CB_RECORDING) { 7100 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkEndCommandBuffer()"); 7101 } 7102 for (auto query : pCB->activeQueries) { 7103 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 7104 DRAWSTATE_INVALID_QUERY, "DS", 7105 "Ending command buffer with in progress query: queryPool %" PRIu64 ", index %d", 7106 (uint64_t)(query.pool), query.index); 7107 } 7108 } 7109 if (VK_FALSE == skipCall) { 7110 loader_platform_thread_unlock_mutex(&globalLock); 7111 result = dev_data->device_dispatch_table->EndCommandBuffer(commandBuffer); 7112 loader_platform_thread_lock_mutex(&globalLock); 7113 if (VK_SUCCESS == result) { 7114 pCB->state = CB_RECORDED; 7115 // Reset CB status flags 7116 pCB->status = 0; 7117 printCB(dev_data, commandBuffer); 7118 } 7119 } else { 7120 result = VK_ERROR_VALIDATION_FAILED_EXT; 7121 } 7122 loader_platform_thread_unlock_mutex(&globalLock); 7123 return result; 7124} 7125 7126VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 7127vkResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) { 7128 VkBool32 skipCall = VK_FALSE; 7129 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7130 loader_platform_thread_lock_mutex(&globalLock); 7131#if MTMERGE 7132 bool commandBufferComplete = false; 7133 // Verify that CB is complete (not in-flight) 7134 skipCall = checkCBCompleted(dev_data, commandBuffer, &commandBufferComplete); 7135 if (!commandBufferComplete) { 7136 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7137 (uint64_t)commandBuffer, __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", 7138 "Resetting CB %p before it has completed. You must check CB " 7139 "flag before calling vkResetCommandBuffer().", 7140 commandBuffer); 7141 } 7142 // Clear memory references as this point. 7143 skipCall |= clear_cmd_buf_and_mem_references(dev_data, commandBuffer); 7144#endif 7145 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7146 VkCommandPool cmdPool = pCB->createInfo.commandPool; 7147 if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) { 7148 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7149 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", 7150 "Attempt to reset command buffer (%#" PRIxLEAST64 ") created from command pool (%#" PRIxLEAST64 7151 ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.", 7152 (uint64_t)commandBuffer, (uint64_t)cmdPool); 7153 } 7154 if (dev_data->globalInFlightCmdBuffers.count(commandBuffer)) { 7155 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 7156 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", 7157 "Attempt to reset command buffer (%#" PRIxLEAST64 ") which is in use.", 7158 reinterpret_cast<uint64_t>(commandBuffer)); 7159 } 7160 loader_platform_thread_unlock_mutex(&globalLock); 7161 if (skipCall != VK_FALSE) 7162 return VK_ERROR_VALIDATION_FAILED_EXT; 7163 VkResult result = dev_data->device_dispatch_table->ResetCommandBuffer(commandBuffer, flags); 7164 if (VK_SUCCESS == result) { 7165 loader_platform_thread_lock_mutex(&globalLock); 7166 resetCB(dev_data, commandBuffer); 7167 loader_platform_thread_unlock_mutex(&globalLock); 7168 } 7169 return result; 7170} 7171#if MTMERGE 7172// TODO : For any vkCmdBind* calls that include an object which has mem bound to it, 7173// need to account for that mem now having binding to given commandBuffer 7174#endif 7175VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7176vkCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) { 7177 VkBool32 skipCall = VK_FALSE; 7178 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7179 loader_platform_thread_lock_mutex(&globalLock); 7180#if MTMERGE 7181 // MTMTODO : Pulled this dead code in during merge, figure out what to do with it 7182#if 0 // FIXME: NEED TO FIX THE FOLLOWING CODE AND REMOVE THIS #if 0 7183 // TODO : If memory bound to pipeline, then need to tie that mem to commandBuffer 7184 if (getPipeline(pipeline)) { 7185 MT_CB_INFO *pCBInfo = get_cmd_buf_info(my_data, commandBuffer); 7186 if (pCBInfo) { 7187 pCBInfo->pipelines[pipelineBindPoint] = pipeline; 7188 } 7189 } 7190 else { 7191 "Attempt to bind Pipeline %p that doesn't exist!", (void*)pipeline); 7192 layerCbMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, pipeline, __LINE__, MEMTRACK_INVALID_OBJECT, (char *) "DS", (char *) str); 7193 } 7194#endif 7195#endif 7196 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7197 if (pCB) { 7198 skipCall |= addCmd(dev_data, pCB, CMD_BINDPIPELINE, "vkCmdBindPipeline()"); 7199 if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (pCB->activeRenderPass)) { 7200 skipCall |= 7201 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, 7202 (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS", 7203 "Incorrectly binding compute pipeline (%#" PRIxLEAST64 ") during active RenderPass (%#" PRIxLEAST64 ")", 7204 (uint64_t)pipeline, (uint64_t)pCB->activeRenderPass); 7205 } 7206 7207 PIPELINE_NODE *pPN = getPipeline(dev_data, pipeline); 7208 if (pPN) { 7209 pCB->lastBoundPipeline = pipeline; 7210 set_cb_pso_status(pCB, pPN); 7211 skipCall |= validatePipelineState(dev_data, pCB, pipelineBindPoint, pipeline); 7212 } else { 7213 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, 7214 (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_PIPELINE, "DS", 7215 "Attempt to bind Pipeline %#" PRIxLEAST64 " that doesn't exist!", (uint64_t)(pipeline)); 7216 } 7217 } 7218 loader_platform_thread_unlock_mutex(&globalLock); 7219 if (VK_FALSE == skipCall) 7220 dev_data->device_dispatch_table->CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline); 7221} 7222 7223VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7224vkCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports) { 7225 VkBool32 skipCall = VK_FALSE; 7226 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7227 loader_platform_thread_lock_mutex(&globalLock); 7228 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7229 if (pCB) { 7230 skipCall |= addCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()"); 7231 pCB->status |= CBSTATUS_VIEWPORT_SET; 7232 pCB->viewports.resize(viewportCount); 7233 memcpy(pCB->viewports.data(), pViewports, viewportCount * sizeof(VkViewport)); 7234 } 7235 loader_platform_thread_unlock_mutex(&globalLock); 7236 if (VK_FALSE == skipCall) 7237 dev_data->device_dispatch_table->CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports); 7238} 7239 7240VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7241vkCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *pScissors) { 7242 VkBool32 skipCall = VK_FALSE; 7243 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7244 loader_platform_thread_lock_mutex(&globalLock); 7245 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7246 if (pCB) { 7247 skipCall |= addCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()"); 7248 pCB->status |= CBSTATUS_SCISSOR_SET; 7249 pCB->scissors.resize(scissorCount); 7250 memcpy(pCB->scissors.data(), pScissors, scissorCount * sizeof(VkRect2D)); 7251 } 7252 loader_platform_thread_unlock_mutex(&globalLock); 7253 if (VK_FALSE == skipCall) 7254 dev_data->device_dispatch_table->CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors); 7255} 7256 7257VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) { 7258 VkBool32 skipCall = VK_FALSE; 7259 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7260 loader_platform_thread_lock_mutex(&globalLock); 7261 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7262 if (pCB) { 7263 skipCall |= addCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()"); 7264 pCB->status |= CBSTATUS_LINE_WIDTH_SET; 7265 pCB->lineWidth = lineWidth; 7266 } 7267 loader_platform_thread_unlock_mutex(&globalLock); 7268 if (VK_FALSE == skipCall) 7269 dev_data->device_dispatch_table->CmdSetLineWidth(commandBuffer, lineWidth); 7270} 7271 7272VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7273vkCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) { 7274 VkBool32 skipCall = VK_FALSE; 7275 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7276 loader_platform_thread_lock_mutex(&globalLock); 7277 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7278 if (pCB) { 7279 skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()"); 7280 pCB->status |= CBSTATUS_DEPTH_BIAS_SET; 7281 pCB->depthBiasConstantFactor = depthBiasConstantFactor; 7282 pCB->depthBiasClamp = depthBiasClamp; 7283 pCB->depthBiasSlopeFactor = depthBiasSlopeFactor; 7284 } 7285 loader_platform_thread_unlock_mutex(&globalLock); 7286 if (VK_FALSE == skipCall) 7287 dev_data->device_dispatch_table->CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, 7288 depthBiasSlopeFactor); 7289} 7290 7291VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) { 7292 VkBool32 skipCall = VK_FALSE; 7293 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7294 loader_platform_thread_lock_mutex(&globalLock); 7295 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7296 if (pCB) { 7297 skipCall |= addCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()"); 7298 pCB->status |= CBSTATUS_BLEND_SET; 7299 memcpy(pCB->blendConstants, blendConstants, 4 * sizeof(float)); 7300 } 7301 loader_platform_thread_unlock_mutex(&globalLock); 7302 if (VK_FALSE == skipCall) 7303 dev_data->device_dispatch_table->CmdSetBlendConstants(commandBuffer, blendConstants); 7304} 7305 7306VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7307vkCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) { 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 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7312 if (pCB) { 7313 skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()"); 7314 pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET; 7315 pCB->minDepthBounds = minDepthBounds; 7316 pCB->maxDepthBounds = maxDepthBounds; 7317 } 7318 loader_platform_thread_unlock_mutex(&globalLock); 7319 if (VK_FALSE == skipCall) 7320 dev_data->device_dispatch_table->CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds); 7321} 7322 7323VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7324vkCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask) { 7325 VkBool32 skipCall = VK_FALSE; 7326 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7327 loader_platform_thread_lock_mutex(&globalLock); 7328 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7329 if (pCB) { 7330 skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()"); 7331 if (faceMask & VK_STENCIL_FACE_FRONT_BIT) { 7332 pCB->front.compareMask = compareMask; 7333 } 7334 if (faceMask & VK_STENCIL_FACE_BACK_BIT) { 7335 pCB->back.compareMask = compareMask; 7336 } 7337 /* TODO: Do we need to track front and back separately? */ 7338 /* TODO: We aren't capturing the faceMask, do we need to? */ 7339 pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET; 7340 } 7341 loader_platform_thread_unlock_mutex(&globalLock); 7342 if (VK_FALSE == skipCall) 7343 dev_data->device_dispatch_table->CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask); 7344} 7345 7346VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7347vkCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) { 7348 VkBool32 skipCall = VK_FALSE; 7349 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7350 loader_platform_thread_lock_mutex(&globalLock); 7351 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7352 if (pCB) { 7353 skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()"); 7354 if (faceMask & VK_STENCIL_FACE_FRONT_BIT) { 7355 pCB->front.writeMask = writeMask; 7356 } 7357 if (faceMask & VK_STENCIL_FACE_BACK_BIT) { 7358 pCB->back.writeMask = writeMask; 7359 } 7360 pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET; 7361 } 7362 loader_platform_thread_unlock_mutex(&globalLock); 7363 if (VK_FALSE == skipCall) 7364 dev_data->device_dispatch_table->CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask); 7365} 7366 7367VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7368vkCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) { 7369 VkBool32 skipCall = VK_FALSE; 7370 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7371 loader_platform_thread_lock_mutex(&globalLock); 7372 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7373 if (pCB) { 7374 skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()"); 7375 if (faceMask & VK_STENCIL_FACE_FRONT_BIT) { 7376 pCB->front.reference = reference; 7377 } 7378 if (faceMask & VK_STENCIL_FACE_BACK_BIT) { 7379 pCB->back.reference = reference; 7380 } 7381 pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET; 7382 } 7383 loader_platform_thread_unlock_mutex(&globalLock); 7384 if (VK_FALSE == skipCall) 7385 dev_data->device_dispatch_table->CmdSetStencilReference(commandBuffer, faceMask, reference); 7386} 7387 7388VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7389vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, 7390 uint32_t firstSet, uint32_t setCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount, 7391 const uint32_t *pDynamicOffsets) { 7392 VkBool32 skipCall = VK_FALSE; 7393 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7394 loader_platform_thread_lock_mutex(&globalLock); 7395#if MTMERGE 7396 // MTMTODO : Merge this with code below 7397 auto cb_data = dev_data->cbMap.find(commandBuffer); 7398 if (cb_data != dev_data->cbMap.end()) { 7399 std::vector<VkDescriptorSet> &activeDescriptorSets = cb_data->second.activeDescriptorSets; 7400 if (activeDescriptorSets.size() < (setCount + firstSet)) { 7401 activeDescriptorSets.resize(setCount + firstSet); 7402 } 7403 for (uint32_t i = 0; i < setCount; ++i) { 7404 activeDescriptorSets[i + firstSet] = pDescriptorSets[i]; 7405 } 7406 } 7407 // TODO : Somewhere need to verify that all textures referenced by shaders in DS are in some type of *SHADER_READ* state 7408#endif 7409 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7410 if (pCB) { 7411 if (pCB->state == CB_RECORDING) { 7412 if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (pCB->activeRenderPass)) { 7413 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 7414 __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS", 7415 "Incorrectly binding compute DescriptorSets during active RenderPass (%#" PRIxLEAST64 ")", 7416 (uint64_t)pCB->activeRenderPass); 7417 } else if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) { 7418 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdBindDescriptorSets"); 7419 } 7420 if (VK_FALSE == skipCall) { 7421 // Track total count of dynamic descriptor types to make sure we have an offset for each one 7422 uint32_t totalDynamicDescriptors = 0; 7423 string errorString = ""; 7424 uint32_t lastSetIndex = firstSet + setCount - 1; 7425 if (lastSetIndex >= pCB->boundDescriptorSets.size()) 7426 pCB->boundDescriptorSets.resize(lastSetIndex + 1); 7427 VkDescriptorSet oldFinalBoundSet = pCB->boundDescriptorSets[lastSetIndex]; 7428 for (uint32_t i = 0; i < setCount; i++) { 7429 SET_NODE *pSet = getSetNode(dev_data, pDescriptorSets[i]); 7430 if (pSet) { 7431 pCB->uniqueBoundSets.insert(pDescriptorSets[i]); 7432 pSet->boundCmdBuffers.insert(commandBuffer); 7433 pCB->lastBoundDescriptorSet = pDescriptorSets[i]; 7434 pCB->lastBoundPipelineLayout = layout; 7435 pCB->boundDescriptorSets[i + firstSet] = pDescriptorSets[i]; 7436 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 7437 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, 7438 DRAWSTATE_NONE, "DS", "DS %#" PRIxLEAST64 " bound on pipeline %s", 7439 (uint64_t)pDescriptorSets[i], string_VkPipelineBindPoint(pipelineBindPoint)); 7440 if (!pSet->pUpdateStructs && (pSet->descriptorCount != 0)) { 7441 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, 7442 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], 7443 __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS", 7444 "DS %#" PRIxLEAST64 7445 " bound but it was never updated. You may want to either update it or not bind it.", 7446 (uint64_t)pDescriptorSets[i]); 7447 } 7448 // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout 7449 if (!verify_set_layout_compatibility(dev_data, pSet, layout, i + firstSet, errorString)) { 7450 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7451 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], 7452 __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS", 7453 "descriptorSet #%u being bound is not compatible with overlapping layout in " 7454 "pipelineLayout due to: %s", 7455 i, errorString.c_str()); 7456 } 7457 if (pSet->pLayout->dynamicDescriptorCount) { 7458 // First make sure we won't overstep bounds of pDynamicOffsets array 7459 if ((totalDynamicDescriptors + pSet->pLayout->dynamicDescriptorCount) > dynamicOffsetCount) { 7460 skipCall |= 7461 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7462 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, 7463 DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS", 7464 "descriptorSet #%u (%#" PRIxLEAST64 7465 ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets " 7466 "array. There must be one dynamic offset for each dynamic descriptor being bound.", 7467 i, (uint64_t)pDescriptorSets[i], pSet->pLayout->dynamicDescriptorCount, 7468 (dynamicOffsetCount - totalDynamicDescriptors)); 7469 } else { // Validate and store dynamic offsets with the set 7470 // Validate Dynamic Offset Minimums 7471 uint32_t cur_dyn_offset = totalDynamicDescriptors; 7472 for (uint32_t d = 0; d < pSet->descriptorCount; d++) { 7473 if (pSet->pLayout->descriptorTypes[d] == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { 7474 if (vk_safe_modulo( 7475 pDynamicOffsets[cur_dyn_offset], 7476 dev_data->physDevProperties.properties.limits.minUniformBufferOffsetAlignment) != 7477 0) { 7478 skipCall |= log_msg( 7479 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7480 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, 7481 DRAWSTATE_INVALID_UNIFORM_BUFFER_OFFSET, "DS", 7482 "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of " 7483 "device limit minUniformBufferOffsetAlignment %#" PRIxLEAST64, 7484 cur_dyn_offset, pDynamicOffsets[cur_dyn_offset], 7485 dev_data->physDevProperties.properties.limits.minUniformBufferOffsetAlignment); 7486 } 7487 cur_dyn_offset++; 7488 } else if (pSet->pLayout->descriptorTypes[d] == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) { 7489 if (vk_safe_modulo( 7490 pDynamicOffsets[cur_dyn_offset], 7491 dev_data->physDevProperties.properties.limits.minStorageBufferOffsetAlignment) != 7492 0) { 7493 skipCall |= log_msg( 7494 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7495 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, 7496 DRAWSTATE_INVALID_STORAGE_BUFFER_OFFSET, "DS", 7497 "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of " 7498 "device limit minStorageBufferOffsetAlignment %#" PRIxLEAST64, 7499 cur_dyn_offset, pDynamicOffsets[cur_dyn_offset], 7500 dev_data->physDevProperties.properties.limits.minStorageBufferOffsetAlignment); 7501 } 7502 cur_dyn_offset++; 7503 } 7504 } 7505 // Keep running total of dynamic descriptor count to verify at the end 7506 totalDynamicDescriptors += pSet->pLayout->dynamicDescriptorCount; 7507 } 7508 } 7509 } else { 7510 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7511 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, 7512 DRAWSTATE_INVALID_SET, "DS", "Attempt to bind DS %#" PRIxLEAST64 " that doesn't exist!", 7513 (uint64_t)pDescriptorSets[i]); 7514 } 7515 } 7516 skipCall |= addCmd(dev_data, pCB, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescrsiptorSets()"); 7517 // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update 7518 if (firstSet > 0) { // Check set #s below the first bound set 7519 for (uint32_t i = 0; i < firstSet; ++i) { 7520 if (pCB->boundDescriptorSets[i] && 7521 !verify_set_layout_compatibility(dev_data, dev_data->setMap[pCB->boundDescriptorSets[i]], layout, i, 7522 errorString)) { 7523 skipCall |= log_msg( 7524 dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 7525 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pCB->boundDescriptorSets[i], __LINE__, 7526 DRAWSTATE_NONE, "DS", 7527 "DescriptorSetDS %#" PRIxLEAST64 7528 " previously bound as set #%u was disturbed by newly bound pipelineLayout (%#" PRIxLEAST64 ")", 7529 (uint64_t)pCB->boundDescriptorSets[i], i, (uint64_t)layout); 7530 pCB->boundDescriptorSets[i] = VK_NULL_HANDLE; 7531 } 7532 } 7533 } 7534 // Check if newly last bound set invalidates any remaining bound sets 7535 if ((pCB->boundDescriptorSets.size() - 1) > (lastSetIndex)) { 7536 if (oldFinalBoundSet && 7537 !verify_set_layout_compatibility(dev_data, dev_data->setMap[oldFinalBoundSet], layout, lastSetIndex, 7538 errorString)) { 7539 skipCall |= 7540 log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 7541 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)oldFinalBoundSet, __LINE__, 7542 DRAWSTATE_NONE, "DS", "DescriptorSetDS %#" PRIxLEAST64 7543 " previously bound as set #%u is incompatible with set %#" PRIxLEAST64 7544 " newly bound as set #%u so set #%u and any subsequent sets were " 7545 "disturbed by newly bound pipelineLayout (%#" PRIxLEAST64 ")", 7546 (uint64_t)oldFinalBoundSet, lastSetIndex, (uint64_t)pCB->boundDescriptorSets[lastSetIndex], 7547 lastSetIndex, lastSetIndex + 1, (uint64_t)layout); 7548 pCB->boundDescriptorSets.resize(lastSetIndex + 1); 7549 } 7550 } 7551 // dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound 7552 if (totalDynamicDescriptors != dynamicOffsetCount) { 7553 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 7554 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__, 7555 DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS", 7556 "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount " 7557 "is %u. It should exactly match the number of dynamic descriptors.", 7558 setCount, totalDynamicDescriptors, dynamicOffsetCount); 7559 } 7560 // Save dynamicOffsets bound to this CB 7561 for (uint32_t i = 0; i < dynamicOffsetCount; i++) { 7562 pCB->dynamicOffsets.emplace_back(pDynamicOffsets[i]); 7563 } 7564 } 7565 } else { 7566 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindDescriptorSets()"); 7567 } 7568 } 7569 loader_platform_thread_unlock_mutex(&globalLock); 7570 if (VK_FALSE == skipCall) 7571 dev_data->device_dispatch_table->CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount, 7572 pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); 7573} 7574 7575VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7576vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) { 7577 VkBool32 skipCall = VK_FALSE; 7578 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7579 loader_platform_thread_lock_mutex(&globalLock); 7580#if MTMERGE 7581 VkDeviceMemory mem; 7582 skipCall = 7583 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)(buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7584 auto cb_data = dev_data->cbMap.find(commandBuffer); 7585 if (cb_data != dev_data->cbMap.end()) { 7586 std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBindIndexBuffer()"); }; 7587 cb_data->second.validate_functions.push_back(function); 7588 } 7589 // TODO : Somewhere need to verify that IBs have correct usage state flagged 7590#endif 7591 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7592 if (pCB) { 7593 skipCall |= addCmd(dev_data, pCB, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()"); 7594 VkDeviceSize offset_align = 0; 7595 switch (indexType) { 7596 case VK_INDEX_TYPE_UINT16: 7597 offset_align = 2; 7598 break; 7599 case VK_INDEX_TYPE_UINT32: 7600 offset_align = 4; 7601 break; 7602 default: 7603 // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0 7604 break; 7605 } 7606 if (!offset_align || (offset % offset_align)) { 7607 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 7608 DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS", 7609 "vkCmdBindIndexBuffer() offset (%#" PRIxLEAST64 ") does not fall on alignment (%s) boundary.", 7610 offset, string_VkIndexType(indexType)); 7611 } 7612 pCB->status |= CBSTATUS_INDEX_BUFFER_BOUND; 7613 } 7614 loader_platform_thread_unlock_mutex(&globalLock); 7615 if (VK_FALSE == skipCall) 7616 dev_data->device_dispatch_table->CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType); 7617} 7618 7619void updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) { 7620 uint32_t end = firstBinding + bindingCount; 7621 if (pCB->currentDrawData.buffers.size() < end) { 7622 pCB->currentDrawData.buffers.resize(end); 7623 } 7624 for (uint32_t i = 0; i < bindingCount; ++i) { 7625 pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i]; 7626 } 7627} 7628 7629void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); } 7630 7631VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, 7632 uint32_t bindingCount, const VkBuffer *pBuffers, 7633 const VkDeviceSize *pOffsets) { 7634 VkBool32 skipCall = VK_FALSE; 7635 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7636 loader_platform_thread_lock_mutex(&globalLock); 7637#if MTMERGE 7638 for (uint32_t i = 0; i < bindingCount; ++i) { 7639 VkDeviceMemory mem; 7640 skipCall |= get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)(pBuffers[i]), 7641 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7642 auto cb_data = dev_data->cbMap.find(commandBuffer); 7643 if (cb_data != dev_data->cbMap.end()) { 7644 std::function<VkBool32()> function = 7645 [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBindVertexBuffers()"); }; 7646 cb_data->second.validate_functions.push_back(function); 7647 } 7648 } 7649 // TODO : Somewhere need to verify that VBs have correct usage state flagged 7650#endif 7651 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7652 if (pCB) { 7653 addCmd(dev_data, pCB, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffer()"); 7654 updateResourceTracking(pCB, firstBinding, bindingCount, pBuffers); 7655 } else { 7656 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindVertexBuffer()"); 7657 } 7658 loader_platform_thread_unlock_mutex(&globalLock); 7659 if (VK_FALSE == skipCall) 7660 dev_data->device_dispatch_table->CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); 7661} 7662 7663#if MTMERGE 7664/* expects globalLock to be held by caller */ 7665bool markStoreImagesAndBuffersAsWritten(VkCommandBuffer commandBuffer) { 7666 bool skip_call = false; 7667 layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7668 auto cb_data = my_data->cbMap.find(commandBuffer); 7669 if (cb_data == my_data->cbMap.end()) 7670 return skip_call; 7671 std::vector<VkDescriptorSet> &activeDescriptorSets = cb_data->second.activeDescriptorSets; 7672 for (auto descriptorSet : activeDescriptorSets) { 7673 auto ds_data = my_data->descriptorSetMap.find(descriptorSet); 7674 if (ds_data == my_data->descriptorSetMap.end()) 7675 continue; 7676 std::vector<VkImageView> images = ds_data->second.images; 7677 std::vector<VkBuffer> buffers = ds_data->second.buffers; 7678 for (auto imageView : images) { 7679 auto iv_data = my_data->imageViewMap.find(imageView); 7680 if (iv_data == my_data->imageViewMap.end()) 7681 continue; 7682 VkImage image = iv_data->second.image; 7683 VkDeviceMemory mem; 7684 skip_call |= 7685 get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 7686 std::function<VkBool32()> function = [=]() { 7687 set_memory_valid(my_data, mem, true, image); 7688 return VK_FALSE; 7689 }; 7690 cb_data->second.validate_functions.push_back(function); 7691 } 7692 for (auto buffer : buffers) { 7693 VkDeviceMemory mem; 7694 skip_call |= 7695 get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7696 std::function<VkBool32()> function = [=]() { 7697 set_memory_valid(my_data, mem, true); 7698 return VK_FALSE; 7699 }; 7700 cb_data->second.validate_functions.push_back(function); 7701 } 7702 } 7703 return skip_call; 7704} 7705#endif 7706 7707VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, 7708 uint32_t firstVertex, uint32_t firstInstance) { 7709 VkBool32 skipCall = VK_FALSE; 7710 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7711 loader_platform_thread_lock_mutex(&globalLock); 7712#if MTMERGE 7713 // MTMTODO : merge with code below 7714 skipCall = markStoreImagesAndBuffersAsWritten(commandBuffer); 7715#endif 7716 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7717 if (pCB) { 7718 skipCall |= addCmd(dev_data, pCB, CMD_DRAW, "vkCmdDraw()"); 7719 pCB->drawCount[DRAW]++; 7720 skipCall |= validate_draw_state(dev_data, pCB, VK_FALSE); 7721 // TODO : Need to pass commandBuffer as srcObj here 7722 skipCall |= 7723 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 7724 __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDraw() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW]++); 7725 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); 7726 if (VK_FALSE == skipCall) { 7727 updateResourceTrackingOnDraw(pCB); 7728 } 7729 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDraw"); 7730 } 7731 loader_platform_thread_unlock_mutex(&globalLock); 7732 if (VK_FALSE == skipCall) 7733 dev_data->device_dispatch_table->CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance); 7734} 7735 7736VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, 7737 uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, 7738 uint32_t firstInstance) { 7739 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7740 VkBool32 skipCall = VK_FALSE; 7741 loader_platform_thread_lock_mutex(&globalLock); 7742#if MTMERGE 7743 // MTMTODO : merge with code below 7744 skipCall = markStoreImagesAndBuffersAsWritten(commandBuffer); 7745#endif 7746 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7747 if (pCB) { 7748 skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXED, "vkCmdDrawIndexed()"); 7749 pCB->drawCount[DRAW_INDEXED]++; 7750 skipCall |= validate_draw_state(dev_data, pCB, VK_TRUE); 7751 // TODO : Need to pass commandBuffer as srcObj here 7752 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 7753 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS", 7754 "vkCmdDrawIndexed() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW_INDEXED]++); 7755 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); 7756 if (VK_FALSE == skipCall) { 7757 updateResourceTrackingOnDraw(pCB); 7758 } 7759 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexed"); 7760 } 7761 loader_platform_thread_unlock_mutex(&globalLock); 7762 if (VK_FALSE == skipCall) 7763 dev_data->device_dispatch_table->CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, 7764 firstInstance); 7765} 7766 7767VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7768vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { 7769 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7770 VkBool32 skipCall = VK_FALSE; 7771 loader_platform_thread_lock_mutex(&globalLock); 7772#if MTMERGE 7773 VkDeviceMemory mem; 7774 // MTMTODO : merge with code below 7775 skipCall = 7776 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7777 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDrawIndirect"); 7778 skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer); 7779#endif 7780 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7781 if (pCB) { 7782 skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDIRECT, "vkCmdDrawIndirect()"); 7783 pCB->drawCount[DRAW_INDIRECT]++; 7784 skipCall |= validate_draw_state(dev_data, pCB, VK_FALSE); 7785 // TODO : Need to pass commandBuffer as srcObj here 7786 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 7787 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS", 7788 "vkCmdDrawIndirect() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW_INDIRECT]++); 7789 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); 7790 if (VK_FALSE == skipCall) { 7791 updateResourceTrackingOnDraw(pCB); 7792 } 7793 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndirect"); 7794 } 7795 loader_platform_thread_unlock_mutex(&globalLock); 7796 if (VK_FALSE == skipCall) 7797 dev_data->device_dispatch_table->CmdDrawIndirect(commandBuffer, buffer, offset, count, stride); 7798} 7799 7800VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7801vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { 7802 VkBool32 skipCall = VK_FALSE; 7803 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7804 loader_platform_thread_lock_mutex(&globalLock); 7805#if MTMERGE 7806 VkDeviceMemory mem; 7807 // MTMTODO : merge with code below 7808 skipCall = 7809 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7810 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDrawIndexedIndirect"); 7811 skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer); 7812#endif 7813 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7814 if (pCB) { 7815 skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXEDINDIRECT, "vkCmdDrawIndexedIndirect()"); 7816 pCB->drawCount[DRAW_INDEXED_INDIRECT]++; 7817 loader_platform_thread_unlock_mutex(&globalLock); 7818 skipCall |= validate_draw_state(dev_data, pCB, VK_TRUE); 7819 loader_platform_thread_lock_mutex(&globalLock); 7820 // TODO : Need to pass commandBuffer as srcObj here 7821 skipCall |= 7822 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 7823 __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDrawIndexedIndirect() call #%" PRIu64 ", reporting DS state:", 7824 g_drawCount[DRAW_INDEXED_INDIRECT]++); 7825 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); 7826 if (VK_FALSE == skipCall) { 7827 updateResourceTrackingOnDraw(pCB); 7828 } 7829 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexedIndirect"); 7830 } 7831 loader_platform_thread_unlock_mutex(&globalLock); 7832 if (VK_FALSE == skipCall) 7833 dev_data->device_dispatch_table->CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride); 7834} 7835 7836VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) { 7837 VkBool32 skipCall = VK_FALSE; 7838 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7839 loader_platform_thread_lock_mutex(&globalLock); 7840#if MTMERGE 7841 skipCall = markStoreImagesAndBuffersAsWritten(commandBuffer); 7842#endif 7843 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7844 if (pCB) { 7845 skipCall |= addCmd(dev_data, pCB, CMD_DISPATCH, "vkCmdDispatch()"); 7846 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatch"); 7847 } 7848 loader_platform_thread_unlock_mutex(&globalLock); 7849 if (VK_FALSE == skipCall) 7850 dev_data->device_dispatch_table->CmdDispatch(commandBuffer, x, y, z); 7851} 7852 7853VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7854vkCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) { 7855 VkBool32 skipCall = VK_FALSE; 7856 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7857 loader_platform_thread_lock_mutex(&globalLock); 7858#if MTMERGE 7859 VkDeviceMemory mem; 7860 skipCall = 7861 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7862 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDispatchIndirect"); 7863 skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer); 7864#endif 7865 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7866 if (pCB) { 7867 skipCall |= addCmd(dev_data, pCB, CMD_DISPATCHINDIRECT, "vkCmdDispatchIndirect()"); 7868 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatchIndirect"); 7869 } 7870 loader_platform_thread_unlock_mutex(&globalLock); 7871 if (VK_FALSE == skipCall) 7872 dev_data->device_dispatch_table->CmdDispatchIndirect(commandBuffer, buffer, offset); 7873} 7874 7875VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, 7876 uint32_t regionCount, const VkBufferCopy *pRegions) { 7877 VkBool32 skipCall = VK_FALSE; 7878 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7879 loader_platform_thread_lock_mutex(&globalLock); 7880#if MTMERGE 7881 VkDeviceMemory mem; 7882 auto cb_data = dev_data->cbMap.find(commandBuffer); 7883 loader_platform_thread_lock_mutex(&globalLock); 7884 skipCall = 7885 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7886 if (cb_data != dev_data->cbMap.end()) { 7887 std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyBuffer()"); }; 7888 cb_data->second.validate_functions.push_back(function); 7889 } 7890 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBuffer"); 7891 skipCall |= 7892 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 7893 if (cb_data != dev_data->cbMap.end()) { 7894 std::function<VkBool32()> function = [=]() { 7895 set_memory_valid(dev_data, mem, true); 7896 return VK_FALSE; 7897 }; 7898 cb_data->second.validate_functions.push_back(function); 7899 } 7900 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBuffer"); 7901 // Validate that SRC & DST buffers have correct usage flags set 7902 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, 7903 "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT"); 7904 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, 7905 "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); 7906#endif 7907 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 7908 if (pCB) { 7909 skipCall |= addCmd(dev_data, pCB, CMD_COPYBUFFER, "vkCmdCopyBuffer()"); 7910 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyBuffer"); 7911 } 7912 loader_platform_thread_unlock_mutex(&globalLock); 7913 if (VK_FALSE == skipCall) 7914 dev_data->device_dispatch_table->CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); 7915} 7916 7917VkBool32 VerifySourceImageLayout(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageSubresourceLayers subLayers, 7918 VkImageLayout srcImageLayout) { 7919 VkBool32 skip_call = VK_FALSE; 7920 7921 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 7922 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 7923 for (uint32_t i = 0; i < subLayers.layerCount; ++i) { 7924 uint32_t layer = i + subLayers.baseArrayLayer; 7925 VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer}; 7926 IMAGE_CMD_BUF_LAYOUT_NODE node; 7927 if (!FindLayout(pCB, srcImage, sub, node)) { 7928 SetLayout(pCB, srcImage, sub, {srcImageLayout, srcImageLayout}); 7929 continue; 7930 } 7931 if (node.layout != srcImageLayout) { 7932 // TODO: Improve log message in the next pass 7933 skip_call |= 7934 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 7935 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose source layout is %s " 7936 "and doesn't match the current layout %s.", 7937 string_VkImageLayout(srcImageLayout), string_VkImageLayout(node.layout)); 7938 } 7939 } 7940 if (srcImageLayout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { 7941 if (srcImageLayout == VK_IMAGE_LAYOUT_GENERAL) { 7942 // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning. 7943 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 7944 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 7945 "Layout for input image should be TRANSFER_SRC_OPTIMAL instead of GENERAL."); 7946 } else { 7947 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 7948 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for input image is %s but can only be " 7949 "TRANSFER_SRC_OPTIMAL or GENERAL.", 7950 string_VkImageLayout(srcImageLayout)); 7951 } 7952 } 7953 return skip_call; 7954} 7955 7956VkBool32 VerifyDestImageLayout(VkCommandBuffer cmdBuffer, VkImage destImage, VkImageSubresourceLayers subLayers, 7957 VkImageLayout destImageLayout) { 7958 VkBool32 skip_call = VK_FALSE; 7959 7960 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 7961 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 7962 for (uint32_t i = 0; i < subLayers.layerCount; ++i) { 7963 uint32_t layer = i + subLayers.baseArrayLayer; 7964 VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer}; 7965 IMAGE_CMD_BUF_LAYOUT_NODE node; 7966 if (!FindLayout(pCB, destImage, sub, node)) { 7967 SetLayout(pCB, destImage, sub, {destImageLayout, destImageLayout}); 7968 continue; 7969 } 7970 if (node.layout != destImageLayout) { 7971 skip_call |= 7972 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 7973 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose dest layout is %s and " 7974 "doesn't match the current layout %s.", 7975 string_VkImageLayout(destImageLayout), string_VkImageLayout(node.layout)); 7976 } 7977 } 7978 if (destImageLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { 7979 if (destImageLayout == VK_IMAGE_LAYOUT_GENERAL) { 7980 // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning. 7981 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 7982 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 7983 "Layout for output image should be TRANSFER_DST_OPTIMAL instead of GENERAL."); 7984 } else { 7985 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 7986 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for output image is %s but can only be " 7987 "TRANSFER_DST_OPTIMAL or GENERAL.", 7988 string_VkImageLayout(destImageLayout)); 7989 } 7990 } 7991 return skip_call; 7992} 7993 7994VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 7995vkCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, 7996 VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) { 7997 VkBool32 skipCall = VK_FALSE; 7998 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 7999 loader_platform_thread_lock_mutex(&globalLock); 8000#if MTMERGE 8001 VkDeviceMemory mem; 8002 auto cb_data = dev_data->cbMap.find(commandBuffer); 8003 // Validate that src & dst images have correct usage flags set 8004 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8005 if (cb_data != dev_data->cbMap.end()) { 8006 std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyImage()", srcImage); }; 8007 cb_data->second.validate_functions.push_back(function); 8008 } 8009 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImage"); 8010 skipCall |= 8011 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8012 if (cb_data != dev_data->cbMap.end()) { 8013 std::function<VkBool32()> function = [=]() { 8014 set_memory_valid(dev_data, mem, true, dstImage); 8015 return VK_FALSE; 8016 }; 8017 cb_data->second.validate_functions.push_back(function); 8018 } 8019 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImage"); 8020 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, 8021 "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT"); 8022 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, 8023 "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT"); 8024#endif 8025 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8026 if (pCB) { 8027 skipCall |= addCmd(dev_data, pCB, CMD_COPYIMAGE, "vkCmdCopyImage()"); 8028 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyImage"); 8029 for (uint32_t i = 0; i < regionCount; ++i) { 8030 skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].srcSubresource, srcImageLayout); 8031 skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].dstSubresource, dstImageLayout); 8032 } 8033 } 8034 loader_platform_thread_unlock_mutex(&globalLock); 8035 if (VK_FALSE == skipCall) 8036 dev_data->device_dispatch_table->CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, 8037 regionCount, pRegions); 8038} 8039 8040VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8041vkCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, 8042 VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) { 8043 VkBool32 skipCall = VK_FALSE; 8044 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8045 loader_platform_thread_lock_mutex(&globalLock); 8046#if MTMERGE 8047 VkDeviceMemory mem; 8048 auto cb_data = dev_data->cbMap.find(commandBuffer); 8049 // Validate that src & dst images have correct usage flags set 8050 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8051 if (cb_data != dev_data->cbMap.end()) { 8052 std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBlitImage()", srcImage); }; 8053 cb_data->second.validate_functions.push_back(function); 8054 } 8055 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdBlitImage"); 8056 skipCall |= 8057 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8058 if (cb_data != dev_data->cbMap.end()) { 8059 std::function<VkBool32()> function = [=]() { 8060 set_memory_valid(dev_data, mem, true, dstImage); 8061 return VK_FALSE; 8062 }; 8063 cb_data->second.validate_functions.push_back(function); 8064 } 8065 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdBlitImage"); 8066 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, 8067 "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT"); 8068 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, 8069 "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT"); 8070#endif 8071 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8072 if (pCB) { 8073 skipCall |= addCmd(dev_data, pCB, CMD_BLITIMAGE, "vkCmdBlitImage()"); 8074 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdBlitImage"); 8075 } 8076 loader_platform_thread_unlock_mutex(&globalLock); 8077 if (VK_FALSE == skipCall) 8078 dev_data->device_dispatch_table->CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, 8079 regionCount, pRegions, filter); 8080} 8081 8082VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, 8083 VkImage dstImage, VkImageLayout dstImageLayout, 8084 uint32_t regionCount, const VkBufferImageCopy *pRegions) { 8085 VkBool32 skipCall = VK_FALSE; 8086 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8087 loader_platform_thread_lock_mutex(&globalLock); 8088#if MTMERGE 8089 VkDeviceMemory mem; 8090 auto cb_data = dev_data->cbMap.find(commandBuffer); 8091 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8092 if (cb_data != dev_data->cbMap.end()) { 8093 std::function<VkBool32()> function = [=]() { 8094 set_memory_valid(dev_data, mem, true, dstImage); 8095 return VK_FALSE; 8096 }; 8097 cb_data->second.validate_functions.push_back(function); 8098 } 8099 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBufferToImage"); 8100 skipCall |= 8101 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 8102 if (cb_data != dev_data->cbMap.end()) { 8103 std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyBufferToImage()"); }; 8104 cb_data->second.validate_functions.push_back(function); 8105 } 8106 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBufferToImage"); 8107 // Validate that src buff & dst image have correct usage flags set 8108 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, 8109 "vkCmdCopyBufferToImage()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT"); 8110 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, 8111 "vkCmdCopyBufferToImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT"); 8112#endif 8113 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8114 if (pCB) { 8115 skipCall |= addCmd(dev_data, pCB, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()"); 8116 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyBufferToImage"); 8117 for (uint32_t i = 0; i < regionCount; ++i) { 8118 skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].imageSubresource, dstImageLayout); 8119 } 8120 } 8121 loader_platform_thread_unlock_mutex(&globalLock); 8122 if (VK_FALSE == skipCall) 8123 dev_data->device_dispatch_table->CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, 8124 pRegions); 8125} 8126 8127VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, 8128 VkImageLayout srcImageLayout, VkBuffer dstBuffer, 8129 uint32_t regionCount, const VkBufferImageCopy *pRegions) { 8130 VkBool32 skipCall = VK_FALSE; 8131 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8132 loader_platform_thread_lock_mutex(&globalLock); 8133#if MTMERGE 8134 VkDeviceMemory mem; 8135 auto cb_data = dev_data->cbMap.find(commandBuffer); 8136 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8137 if (cb_data != dev_data->cbMap.end()) { 8138 std::function<VkBool32()> function = 8139 [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyImageToBuffer()", srcImage); }; 8140 cb_data->second.validate_functions.push_back(function); 8141 } 8142 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImageToBuffer"); 8143 skipCall |= 8144 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 8145 if (cb_data != dev_data->cbMap.end()) { 8146 std::function<VkBool32()> function = [=]() { 8147 set_memory_valid(dev_data, mem, true); 8148 return VK_FALSE; 8149 }; 8150 cb_data->second.validate_functions.push_back(function); 8151 } 8152 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImageToBuffer"); 8153 // Validate that dst buff & src image have correct usage flags set 8154 skipCall |= validate_image_usage_flags(dev_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, 8155 "vkCmdCopyImageToBuffer()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT"); 8156 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, 8157 "vkCmdCopyImageToBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); 8158#endif 8159 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8160 if (pCB) { 8161 skipCall |= addCmd(dev_data, pCB, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()"); 8162 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyImageToBuffer"); 8163 for (uint32_t i = 0; i < regionCount; ++i) { 8164 skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].imageSubresource, srcImageLayout); 8165 } 8166 } 8167 loader_platform_thread_unlock_mutex(&globalLock); 8168 if (VK_FALSE == skipCall) 8169 dev_data->device_dispatch_table->CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, 8170 pRegions); 8171} 8172 8173VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, 8174 VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t *pData) { 8175 VkBool32 skipCall = VK_FALSE; 8176 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8177 loader_platform_thread_lock_mutex(&globalLock); 8178#if MTMERGE 8179 VkDeviceMemory mem; 8180 auto cb_data = dev_data->cbMap.find(commandBuffer); 8181 skipCall = 8182 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 8183 if (cb_data != dev_data->cbMap.end()) { 8184 std::function<VkBool32()> function = [=]() { 8185 set_memory_valid(dev_data, mem, true); 8186 return VK_FALSE; 8187 }; 8188 cb_data->second.validate_functions.push_back(function); 8189 } 8190 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdUpdateBuffer"); 8191 // Validate that dst buff has correct usage flags set 8192 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, 8193 "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); 8194#endif 8195 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8196 if (pCB) { 8197 skipCall |= addCmd(dev_data, pCB, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()"); 8198 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyUpdateBuffer"); 8199 } 8200 loader_platform_thread_unlock_mutex(&globalLock); 8201 if (VK_FALSE == skipCall) 8202 dev_data->device_dispatch_table->CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData); 8203} 8204 8205VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8206vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) { 8207 VkBool32 skipCall = VK_FALSE; 8208 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8209 loader_platform_thread_lock_mutex(&globalLock); 8210#if MTMERGE 8211 VkDeviceMemory mem; 8212 auto cb_data = dev_data->cbMap.find(commandBuffer); 8213 skipCall = 8214 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 8215 if (cb_data != dev_data->cbMap.end()) { 8216 std::function<VkBool32()> function = [=]() { 8217 set_memory_valid(dev_data, mem, true); 8218 return VK_FALSE; 8219 }; 8220 cb_data->second.validate_functions.push_back(function); 8221 } 8222 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdFillBuffer"); 8223 // Validate that dst buff has correct usage flags set 8224 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, 8225 "vkCmdFillBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); 8226#endif 8227 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8228 if (pCB) { 8229 skipCall |= addCmd(dev_data, pCB, CMD_FILLBUFFER, "vkCmdFillBuffer()"); 8230 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyFillBuffer"); 8231 } 8232 loader_platform_thread_unlock_mutex(&globalLock); 8233 if (VK_FALSE == skipCall) 8234 dev_data->device_dispatch_table->CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data); 8235} 8236 8237VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, 8238 const VkClearAttachment *pAttachments, uint32_t rectCount, 8239 const VkClearRect *pRects) { 8240 VkBool32 skipCall = VK_FALSE; 8241 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8242 loader_platform_thread_lock_mutex(&globalLock); 8243 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8244 if (pCB) { 8245 skipCall |= addCmd(dev_data, pCB, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()"); 8246 // Warn if this is issued prior to Draw Cmd and clearing the entire attachment 8247 if (!hasDrawCmd(pCB) && (pCB->activeRenderPassBeginInfo.renderArea.extent.width == pRects[0].rect.extent.width) && 8248 (pCB->activeRenderPassBeginInfo.renderArea.extent.height == pRects[0].rect.extent.height)) { 8249 // TODO : commandBuffer should be srcObj 8250 // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass) 8251 // 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 8252 // call CmdClearAttachments 8253 // Otherwise this seems more like a performance warning. 8254 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 8255 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 0, DRAWSTATE_CLEAR_CMD_BEFORE_DRAW, "DS", 8256 "vkCmdClearAttachments() issued on CB object 0x%" PRIxLEAST64 " prior to any Draw Cmds." 8257 " It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.", 8258 (uint64_t)(commandBuffer)); 8259 } 8260 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdClearAttachments"); 8261 } 8262 8263 // Validate that attachment is in reference list of active subpass 8264 if (pCB->activeRenderPass) { 8265 const VkRenderPassCreateInfo *pRPCI = dev_data->renderPassMap[pCB->activeRenderPass]->pCreateInfo; 8266 const VkSubpassDescription *pSD = &pRPCI->pSubpasses[pCB->activeSubpass]; 8267 8268 for (uint32_t attachment_idx = 0; attachment_idx < attachmentCount; attachment_idx++) { 8269 const VkClearAttachment *attachment = &pAttachments[attachment_idx]; 8270 if (attachment->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { 8271 VkBool32 found = VK_FALSE; 8272 for (uint32_t i = 0; i < pSD->colorAttachmentCount; i++) { 8273 if (attachment->colorAttachment == pSD->pColorAttachments[i].attachment) { 8274 found = VK_TRUE; 8275 break; 8276 } 8277 } 8278 if (VK_FALSE == found) { 8279 skipCall |= log_msg( 8280 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 8281 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS", 8282 "vkCmdClearAttachments() attachment index %d not found in attachment reference array of active subpass %d", 8283 attachment->colorAttachment, pCB->activeSubpass); 8284 } 8285 } else if (attachment->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { 8286 if (!pSD->pDepthStencilAttachment || // Says no DS will be used in active subpass 8287 (pSD->pDepthStencilAttachment->attachment == 8288 VK_ATTACHMENT_UNUSED)) { // Says no DS will be used in active subpass 8289 8290 skipCall |= log_msg( 8291 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 8292 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS", 8293 "vkCmdClearAttachments() attachment index %d does not match depthStencilAttachment.attachment (%d) found " 8294 "in active subpass %d", 8295 attachment->colorAttachment, 8296 (pSD->pDepthStencilAttachment) ? pSD->pDepthStencilAttachment->attachment : VK_ATTACHMENT_UNUSED, 8297 pCB->activeSubpass); 8298 } 8299 } 8300 } 8301 } 8302 loader_platform_thread_unlock_mutex(&globalLock); 8303 if (VK_FALSE == skipCall) 8304 dev_data->device_dispatch_table->CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects); 8305} 8306 8307VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, 8308 VkImageLayout imageLayout, const VkClearColorValue *pColor, 8309 uint32_t rangeCount, const VkImageSubresourceRange *pRanges) { 8310 VkBool32 skipCall = VK_FALSE; 8311 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8312 loader_platform_thread_lock_mutex(&globalLock); 8313#if MTMERGE 8314 // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state 8315 VkDeviceMemory mem; 8316 auto cb_data = dev_data->cbMap.find(commandBuffer); 8317 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8318 if (cb_data != dev_data->cbMap.end()) { 8319 std::function<VkBool32()> function = [=]() { 8320 set_memory_valid(dev_data, mem, true, image); 8321 return VK_FALSE; 8322 }; 8323 cb_data->second.validate_functions.push_back(function); 8324 } 8325 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdClearColorImage"); 8326#endif 8327 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8328 if (pCB) { 8329 skipCall |= addCmd(dev_data, pCB, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()"); 8330 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdClearColorImage"); 8331 } 8332 loader_platform_thread_unlock_mutex(&globalLock); 8333 if (VK_FALSE == skipCall) 8334 dev_data->device_dispatch_table->CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges); 8335} 8336 8337VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8338vkCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, 8339 const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount, 8340 const VkImageSubresourceRange *pRanges) { 8341 VkBool32 skipCall = VK_FALSE; 8342 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8343 loader_platform_thread_lock_mutex(&globalLock); 8344#if MTMERGE 8345 // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state 8346 VkDeviceMemory mem; 8347 auto cb_data = dev_data->cbMap.find(commandBuffer); 8348 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8349 if (cb_data != dev_data->cbMap.end()) { 8350 std::function<VkBool32()> function = [=]() { 8351 set_memory_valid(dev_data, mem, true, image); 8352 return VK_FALSE; 8353 }; 8354 cb_data->second.validate_functions.push_back(function); 8355 } 8356 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdClearDepthStencilImage"); 8357#endif 8358 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8359 if (pCB) { 8360 skipCall |= addCmd(dev_data, pCB, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()"); 8361 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdClearDepthStencilImage"); 8362 } 8363 loader_platform_thread_unlock_mutex(&globalLock); 8364 if (VK_FALSE == skipCall) 8365 dev_data->device_dispatch_table->CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, 8366 pRanges); 8367} 8368 8369VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8370vkCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, 8371 VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve *pRegions) { 8372 VkBool32 skipCall = VK_FALSE; 8373 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8374 loader_platform_thread_lock_mutex(&globalLock); 8375#if MTMERGE 8376 auto cb_data = dev_data->cbMap.find(commandBuffer); 8377 VkDeviceMemory mem; 8378 skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8379 if (cb_data != dev_data->cbMap.end()) { 8380 std::function<VkBool32()> function = 8381 [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdResolveImage()", srcImage); }; 8382 cb_data->second.validate_functions.push_back(function); 8383 } 8384 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdResolveImage"); 8385 skipCall |= 8386 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 8387 if (cb_data != dev_data->cbMap.end()) { 8388 std::function<VkBool32()> function = [=]() { 8389 set_memory_valid(dev_data, mem, true, dstImage); 8390 return VK_FALSE; 8391 }; 8392 cb_data->second.validate_functions.push_back(function); 8393 } 8394 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdResolveImage"); 8395#endif 8396 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8397 if (pCB) { 8398 skipCall |= addCmd(dev_data, pCB, CMD_RESOLVEIMAGE, "vkCmdResolveImage()"); 8399 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdResolveImage"); 8400 } 8401 loader_platform_thread_unlock_mutex(&globalLock); 8402 if (VK_FALSE == skipCall) 8403 dev_data->device_dispatch_table->CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, 8404 regionCount, pRegions); 8405} 8406 8407VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8408vkCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { 8409 VkBool32 skipCall = VK_FALSE; 8410 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8411 loader_platform_thread_lock_mutex(&globalLock); 8412 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8413 if (pCB) { 8414 skipCall |= addCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()"); 8415 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent"); 8416 pCB->events.push_back(event); 8417 pCB->eventToStageMap[event] = stageMask; 8418 } 8419 loader_platform_thread_unlock_mutex(&globalLock); 8420 if (VK_FALSE == skipCall) 8421 dev_data->device_dispatch_table->CmdSetEvent(commandBuffer, event, stageMask); 8422} 8423 8424VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8425vkCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { 8426 VkBool32 skipCall = VK_FALSE; 8427 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8428 loader_platform_thread_lock_mutex(&globalLock); 8429 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8430 if (pCB) { 8431 skipCall |= addCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()"); 8432 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent"); 8433 pCB->events.push_back(event); 8434 } 8435 loader_platform_thread_unlock_mutex(&globalLock); 8436 if (VK_FALSE == skipCall) 8437 dev_data->device_dispatch_table->CmdResetEvent(commandBuffer, event, stageMask); 8438} 8439 8440VkBool32 TransitionImageLayouts(VkCommandBuffer cmdBuffer, uint32_t memBarrierCount, const VkImageMemoryBarrier *pImgMemBarriers) { 8441 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 8442 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 8443 VkBool32 skip = VK_FALSE; 8444 uint32_t levelCount = 0; 8445 uint32_t layerCount = 0; 8446 8447 for (uint32_t i = 0; i < memBarrierCount; ++i) { 8448 auto mem_barrier = &pImgMemBarriers[i]; 8449 if (!mem_barrier) 8450 continue; 8451 // TODO: Do not iterate over every possibility - consolidate where 8452 // possible 8453 ResolveRemainingLevelsLayers(dev_data, &levelCount, &layerCount, mem_barrier->subresourceRange, mem_barrier->image); 8454 8455 for (uint32_t j = 0; j < levelCount; j++) { 8456 uint32_t level = mem_barrier->subresourceRange.baseMipLevel + j; 8457 for (uint32_t k = 0; k < layerCount; k++) { 8458 uint32_t layer = mem_barrier->subresourceRange.baseArrayLayer + k; 8459 VkImageSubresource sub = {mem_barrier->subresourceRange.aspectMask, level, layer}; 8460 IMAGE_CMD_BUF_LAYOUT_NODE node; 8461 if (!FindLayout(pCB, mem_barrier->image, sub, node)) { 8462 SetLayout(pCB, mem_barrier->image, sub, {mem_barrier->oldLayout, mem_barrier->newLayout}); 8463 continue; 8464 } 8465 if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) { 8466 // TODO: Set memory invalid which is in mem_tracker currently 8467 } else if (node.layout != mem_barrier->oldLayout) { 8468 skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 8469 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "You cannot transition the layout from %s " 8470 "when current layout is %s.", 8471 string_VkImageLayout(mem_barrier->oldLayout), string_VkImageLayout(node.layout)); 8472 } 8473 SetLayout(pCB, mem_barrier->image, sub, mem_barrier->newLayout); 8474 } 8475 } 8476 } 8477 return skip; 8478} 8479 8480// Print readable FlagBits in FlagMask 8481std::string string_VkAccessFlags(VkAccessFlags accessMask) { 8482 std::string result; 8483 std::string separator; 8484 8485 if (accessMask == 0) { 8486 result = "[None]"; 8487 } else { 8488 result = "["; 8489 for (auto i = 0; i < 32; i++) { 8490 if (accessMask & (1 << i)) { 8491 result = result + separator + string_VkAccessFlagBits((VkAccessFlagBits)(1 << i)); 8492 separator = " | "; 8493 } 8494 } 8495 result = result + "]"; 8496 } 8497 return result; 8498} 8499 8500// AccessFlags MUST have 'required_bit' set, and may have one or more of 'optional_bits' set. 8501// If required_bit is zero, accessMask must have at least one of 'optional_bits' set 8502// TODO: Add tracking to ensure that at least one barrier has been set for these layout transitions 8503VkBool32 ValidateMaskBits(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask, 8504 const VkImageLayout &layout, VkAccessFlags required_bit, VkAccessFlags optional_bits, const char *type) { 8505 VkBool32 skip_call = VK_FALSE; 8506 8507 if ((accessMask & required_bit) || (!required_bit && (accessMask & optional_bits))) { 8508 if (accessMask & !(required_bit | optional_bits)) { 8509 // TODO: Verify against Valid Use 8510 skip_call |= 8511 log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8512 DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask %d %s are specified when layout is %s.", 8513 type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout)); 8514 } 8515 } else { 8516 if (!required_bit) { 8517 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8518 DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must contain at least one of access bits %d " 8519 "%s when layout is %s, unless the app has previously added a " 8520 "barrier for this transition.", 8521 type, accessMask, string_VkAccessFlags(accessMask).c_str(), optional_bits, 8522 string_VkAccessFlags(optional_bits).c_str(), string_VkImageLayout(layout)); 8523 } else { 8524 std::string opt_bits; 8525 if (optional_bits != 0) { 8526 std::stringstream ss; 8527 ss << optional_bits; 8528 opt_bits = "and may have optional bits " + ss.str() + ' ' + string_VkAccessFlags(optional_bits); 8529 } 8530 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8531 DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must have required access bit %d %s %s when " 8532 "layout is %s, unless the app has previously added a barrier for " 8533 "this transition.", 8534 type, accessMask, string_VkAccessFlags(accessMask).c_str(), required_bit, 8535 string_VkAccessFlags(required_bit).c_str(), opt_bits.c_str(), string_VkImageLayout(layout)); 8536 } 8537 } 8538 return skip_call; 8539} 8540 8541VkBool32 ValidateMaskBitsFromLayouts(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask, 8542 const VkImageLayout &layout, const char *type) { 8543 VkBool32 skip_call = VK_FALSE; 8544 switch (layout) { 8545 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: { 8546 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 8547 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, type); 8548 break; 8549 } 8550 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: { 8551 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, 8552 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, type); 8553 break; 8554 } 8555 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: { 8556 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_WRITE_BIT, 0, type); 8557 break; 8558 } 8559 case VK_IMAGE_LAYOUT_PREINITIALIZED: { 8560 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_HOST_WRITE_BIT, 0, type); 8561 break; 8562 } 8563 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: { 8564 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0, 8565 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type); 8566 break; 8567 } 8568 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: { 8569 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0, 8570 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type); 8571 break; 8572 } 8573 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: { 8574 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_READ_BIT, 0, type); 8575 break; 8576 } 8577 case VK_IMAGE_LAYOUT_UNDEFINED: { 8578 if (accessMask != 0) { 8579 // TODO: Verify against Valid Use section spec 8580 skip_call |= 8581 log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8582 DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask %d %s are specified when layout is %s.", 8583 type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout)); 8584 } 8585 break; 8586 } 8587 case VK_IMAGE_LAYOUT_GENERAL: 8588 default: { break; } 8589 } 8590 return skip_call; 8591} 8592 8593VkBool32 ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount, 8594 const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount, 8595 const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount, 8596 const VkImageMemoryBarrier *pImageMemBarriers) { 8597 VkBool32 skip_call = VK_FALSE; 8598 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 8599 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 8600 if (pCB->activeRenderPass && memBarrierCount) { 8601 if (!dev_data->renderPassMap[pCB->activeRenderPass]->hasSelfDependency[pCB->activeSubpass]) { 8602 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8603 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Barriers cannot be set during subpass %d " 8604 "with no self dependency specified.", 8605 funcName, pCB->activeSubpass); 8606 } 8607 } 8608 for (uint32_t i = 0; i < imageMemBarrierCount; ++i) { 8609 auto mem_barrier = &pImageMemBarriers[i]; 8610 auto image_data = dev_data->imageMap.find(mem_barrier->image); 8611 if (image_data != dev_data->imageMap.end()) { 8612 uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex; 8613 uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex; 8614 if (image_data->second.createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) { 8615 // srcQueueFamilyIndex and dstQueueFamilyIndex must both 8616 // be VK_QUEUE_FAMILY_IGNORED 8617 if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) { 8618 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 8619 __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS", 8620 "%s: Image Barrier for image 0x%" PRIx64 " was created with sharingMode of " 8621 "VK_SHARING_MODE_CONCURRENT. Src and dst " 8622 " queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.", 8623 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image)); 8624 } 8625 } else { 8626 // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and 8627 // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED, 8628 // or both be a valid queue family 8629 if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) && 8630 (src_q_f_index != dst_q_f_index)) { 8631 skip_call |= 8632 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8633 DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64 " was created with sharingMode " 8634 "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or " 8635 "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both " 8636 "must be.", 8637 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image)); 8638 } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) && 8639 ((src_q_f_index >= dev_data->physDevProperties.queue_family_properties.size()) || 8640 (dst_q_f_index >= dev_data->physDevProperties.queue_family_properties.size()))) { 8641 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 8642 __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS", 8643 "%s: Image 0x%" PRIx64 " was created with sharingMode " 8644 "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d" 8645 " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER 8646 "queueFamilies crated for this device.", 8647 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image), src_q_f_index, 8648 dst_q_f_index, dev_data->physDevProperties.queue_family_properties.size()); 8649 } 8650 } 8651 } 8652 8653 if (mem_barrier) { 8654 skip_call |= 8655 ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source"); 8656 skip_call |= 8657 ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest"); 8658 if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) { 8659 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8660 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image Layout cannot be transitioned to UNDEFINED or " 8661 "PREINITIALIZED.", 8662 funcName); 8663 } 8664 auto image_data = dev_data->imageMap.find(mem_barrier->image); 8665 VkFormat format; 8666 uint32_t arrayLayers, mipLevels; 8667 bool imageFound = false; 8668 if (image_data != dev_data->imageMap.end()) { 8669 format = image_data->second.createInfo.format; 8670 arrayLayers = image_data->second.createInfo.arrayLayers; 8671 mipLevels = image_data->second.createInfo.mipLevels; 8672 imageFound = true; 8673 } else if (dev_data->device_extensions.wsi_enabled) { 8674 auto imageswap_data = dev_data->device_extensions.imageToSwapchainMap.find(mem_barrier->image); 8675 if (imageswap_data != dev_data->device_extensions.imageToSwapchainMap.end()) { 8676 auto swapchain_data = dev_data->device_extensions.swapchainMap.find(imageswap_data->second); 8677 if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) { 8678 format = swapchain_data->second->createInfo.imageFormat; 8679 arrayLayers = swapchain_data->second->createInfo.imageArrayLayers; 8680 mipLevels = 1; 8681 imageFound = true; 8682 } 8683 } 8684 } 8685 if (imageFound) { 8686 if (vk_format_is_depth_and_stencil(format) && 8687 (!(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) || 8688 !(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT))) { 8689 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8690 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image is a depth and stencil format and thus must " 8691 "have both VK_IMAGE_ASPECT_DEPTH_BIT and " 8692 "VK_IMAGE_ASPECT_STENCIL_BIT set.", 8693 funcName); 8694 } 8695 if ((mem_barrier->subresourceRange.baseArrayLayer + mem_barrier->subresourceRange.layerCount) > arrayLayers) { 8696 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8697 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the " 8698 "baseArrayLayer (%d) and layerCount (%d) be less " 8699 "than or equal to the total number of layers (%d).", 8700 funcName, mem_barrier->subresourceRange.baseArrayLayer, mem_barrier->subresourceRange.layerCount, 8701 arrayLayers); 8702 } 8703 if ((mem_barrier->subresourceRange.baseMipLevel + mem_barrier->subresourceRange.levelCount) > mipLevels) { 8704 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8705 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the baseMipLevel " 8706 "(%d) and levelCount (%d) be less than or equal to " 8707 "the total number of levels (%d).", 8708 funcName, mem_barrier->subresourceRange.baseMipLevel, mem_barrier->subresourceRange.levelCount, 8709 mipLevels); 8710 } 8711 } 8712 } 8713 } 8714 for (uint32_t i = 0; i < bufferBarrierCount; ++i) { 8715 auto mem_barrier = &pBufferMemBarriers[i]; 8716 if (pCB->activeRenderPass) { 8717 skip_call |= 8718 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8719 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barriers cannot be used during a render pass.", funcName); 8720 } 8721 if (!mem_barrier) 8722 continue; 8723 8724 // Validate buffer barrier queue family indices 8725 if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED && 8726 mem_barrier->srcQueueFamilyIndex >= dev_data->physDevProperties.queue_family_properties.size()) || 8727 (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED && 8728 mem_barrier->dstQueueFamilyIndex >= dev_data->physDevProperties.queue_family_properties.size())) { 8729 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8730 DRAWSTATE_INVALID_QUEUE_INDEX, "DS", 8731 "%s: Buffer Barrier 0x%" PRIx64 " has QueueFamilyIndex greater " 8732 "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.", 8733 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer), 8734 dev_data->physDevProperties.queue_family_properties.size()); 8735 } 8736 8737 auto buffer_data = dev_data->bufferMap.find(mem_barrier->buffer); 8738 uint64_t buffer_size = 8739 buffer_data->second.create_info ? reinterpret_cast<uint64_t &>(buffer_data->second.create_info->size) : 0; 8740 if (buffer_data != dev_data->bufferMap.end()) { 8741 if (mem_barrier->offset >= buffer_size) { 8742 skip_call |= 8743 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8744 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset %" PRIu64 8745 " whose sum is not less than total size %" PRIu64 ".", 8746 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer), 8747 reinterpret_cast<const uint64_t &>(mem_barrier->offset), buffer_size); 8748 } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) { 8749 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 8750 __LINE__, DRAWSTATE_INVALID_BARRIER, "DS", 8751 "%s: Buffer Barrier 0x%" PRIx64 " has offset %" PRIu64 " and size %" PRIu64 8752 " whose sum is greater than total size %" PRIu64 ".", 8753 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer), 8754 reinterpret_cast<const uint64_t &>(mem_barrier->offset), 8755 reinterpret_cast<const uint64_t &>(mem_barrier->size), buffer_size); 8756 } 8757 } 8758 } 8759 return skip_call; 8760} 8761 8762VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8763vkCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags sourceStageMask, 8764 VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, 8765 uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, 8766 uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) { 8767 VkBool32 skipCall = VK_FALSE; 8768 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8769 loader_platform_thread_lock_mutex(&globalLock); 8770 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8771 if (pCB) { 8772 VkPipelineStageFlags stageMask = 0; 8773 for (uint32_t i = 0; i < eventCount; ++i) { 8774 pCB->waitedEvents.push_back(pEvents[i]); 8775 pCB->events.push_back(pEvents[i]); 8776 auto event_data = pCB->eventToStageMap.find(pEvents[i]); 8777 if (event_data != pCB->eventToStageMap.end()) { 8778 stageMask |= event_data->second; 8779 } else { 8780 auto global_event_data = dev_data->eventMap.find(pEvents[i]); 8781 if (global_event_data == dev_data->eventMap.end()) { 8782 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT, 8783 reinterpret_cast<const uint64_t &>(pEvents[i]), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", 8784 "Fence 0x%" PRIx64 " cannot be waited on if it has never been set.", 8785 reinterpret_cast<const uint64_t &>(pEvents[i])); 8786 } else { 8787 stageMask |= global_event_data->second.stageMask; 8788 } 8789 } 8790 } 8791 if (sourceStageMask != stageMask) { 8792 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8793 DRAWSTATE_INVALID_FENCE, "DS", "srcStageMask in vkCmdWaitEvents must be the bitwise OR of the " 8794 "stageMask parameters used in calls to vkCmdSetEvent and " 8795 "VK_PIPELINE_STAGE_HOST_BIT if used with vkSetEvent."); 8796 } 8797 if (pCB->state == CB_RECORDING) { 8798 skipCall |= addCmd(dev_data, pCB, CMD_WAITEVENTS, "vkCmdWaitEvents()"); 8799 } else { 8800 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWaitEvents()"); 8801 } 8802 skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers); 8803 skipCall |= 8804 ValidateBarriers("vkCmdWaitEvents", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, 8805 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); 8806 } 8807 loader_platform_thread_unlock_mutex(&globalLock); 8808 if (VK_FALSE == skipCall) 8809 dev_data->device_dispatch_table->CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask, 8810 memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, 8811 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); 8812} 8813 8814VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8815vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, 8816 VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, 8817 uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, 8818 uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) { 8819 VkBool32 skipCall = VK_FALSE; 8820 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8821 loader_platform_thread_lock_mutex(&globalLock); 8822 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8823 if (pCB) { 8824 skipCall |= addCmd(dev_data, pCB, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()"); 8825 skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers); 8826 skipCall |= 8827 ValidateBarriers("vkCmdPipelineBarrier", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, 8828 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); 8829 } 8830 loader_platform_thread_unlock_mutex(&globalLock); 8831 if (VK_FALSE == skipCall) 8832 dev_data->device_dispatch_table->CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, 8833 memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, 8834 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); 8835} 8836 8837VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8838vkCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) { 8839 VkBool32 skipCall = VK_FALSE; 8840 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8841 loader_platform_thread_lock_mutex(&globalLock); 8842 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8843 if (pCB) { 8844 QueryObject query = {queryPool, slot}; 8845 pCB->activeQueries.insert(query); 8846 if (!pCB->startedQueries.count(query)) { 8847 pCB->startedQueries.insert(query); 8848 } 8849 skipCall |= addCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()"); 8850 } 8851 loader_platform_thread_unlock_mutex(&globalLock); 8852 if (VK_FALSE == skipCall) 8853 dev_data->device_dispatch_table->CmdBeginQuery(commandBuffer, queryPool, slot, flags); 8854} 8855 8856VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) { 8857 VkBool32 skipCall = VK_FALSE; 8858 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8859 loader_platform_thread_lock_mutex(&globalLock); 8860 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8861 if (pCB) { 8862 QueryObject query = {queryPool, slot}; 8863 if (!pCB->activeQueries.count(query)) { 8864 skipCall |= 8865 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 8866 DRAWSTATE_INVALID_QUERY, "DS", "Ending a query before it was started: queryPool %" PRIu64 ", index %d", 8867 (uint64_t)(queryPool), slot); 8868 } else { 8869 pCB->activeQueries.erase(query); 8870 } 8871 pCB->queryToStateMap[query] = 1; 8872 if (pCB->state == CB_RECORDING) { 8873 skipCall |= addCmd(dev_data, pCB, CMD_ENDQUERY, "VkCmdEndQuery()"); 8874 } else { 8875 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdEndQuery()"); 8876 } 8877 } 8878 loader_platform_thread_unlock_mutex(&globalLock); 8879 if (VK_FALSE == skipCall) 8880 dev_data->device_dispatch_table->CmdEndQuery(commandBuffer, queryPool, slot); 8881} 8882 8883VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8884vkCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) { 8885 VkBool32 skipCall = VK_FALSE; 8886 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8887 loader_platform_thread_lock_mutex(&globalLock); 8888 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8889 if (pCB) { 8890 for (uint32_t i = 0; i < queryCount; i++) { 8891 QueryObject query = {queryPool, firstQuery + i}; 8892 pCB->waitedEventsBeforeQueryReset[query] = pCB->waitedEvents; 8893 pCB->queryToStateMap[query] = 0; 8894 } 8895 if (pCB->state == CB_RECORDING) { 8896 skipCall |= addCmd(dev_data, pCB, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()"); 8897 } else { 8898 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdResetQueryPool()"); 8899 } 8900 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdQueryPool"); 8901 } 8902 loader_platform_thread_unlock_mutex(&globalLock); 8903 if (VK_FALSE == skipCall) 8904 dev_data->device_dispatch_table->CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount); 8905} 8906 8907VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8908vkCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, 8909 VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) { 8910 VkBool32 skipCall = VK_FALSE; 8911 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8912 loader_platform_thread_lock_mutex(&globalLock); 8913 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8914#if MTMERGE 8915 VkDeviceMemory mem; 8916 auto cb_data = dev_data->cbMap.find(commandBuffer); 8917 skipCall |= 8918 get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); 8919 if (cb_data != dev_data->cbMap.end()) { 8920 std::function<VkBool32()> function = [=]() { 8921 set_memory_valid(dev_data, mem, true); 8922 return VK_FALSE; 8923 }; 8924 cb_data->second.validate_functions.push_back(function); 8925 } 8926 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyQueryPoolResults"); 8927 // Validate that DST buffer has correct usage flags set 8928 skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, 8929 "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); 8930#endif 8931 if (pCB) { 8932 for (uint32_t i = 0; i < queryCount; i++) { 8933 QueryObject query = {queryPool, firstQuery + i}; 8934 if (!pCB->queryToStateMap[query]) { 8935 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 8936 __LINE__, DRAWSTATE_INVALID_QUERY, "DS", 8937 "Requesting a copy from query to buffer with invalid query: queryPool %" PRIu64 ", index %d", 8938 (uint64_t)(queryPool), firstQuery + i); 8939 } 8940 } 8941 if (pCB->state == CB_RECORDING) { 8942 skipCall |= addCmd(dev_data, pCB, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()"); 8943 } else { 8944 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdCopyQueryPoolResults()"); 8945 } 8946 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyQueryPoolResults"); 8947 } 8948 loader_platform_thread_unlock_mutex(&globalLock); 8949 if (VK_FALSE == skipCall) 8950 dev_data->device_dispatch_table->CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, 8951 dstOffset, stride, flags); 8952} 8953 8954VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, 8955 VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, 8956 const void *pValues) { 8957 bool skipCall = false; 8958 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8959 loader_platform_thread_lock_mutex(&globalLock); 8960 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8961 if (pCB) { 8962 if (pCB->state == CB_RECORDING) { 8963 skipCall |= addCmd(dev_data, pCB, CMD_PUSHCONSTANTS, "vkCmdPushConstants()"); 8964 } else { 8965 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdPushConstants()"); 8966 } 8967 } 8968 if ((offset + size) > dev_data->physDevProperties.properties.limits.maxPushConstantsSize) { 8969 skipCall |= validatePushConstantSize(dev_data, offset, size, "vkCmdPushConstants()"); 8970 } 8971 // TODO : Add warning if push constant update doesn't align with range 8972 loader_platform_thread_unlock_mutex(&globalLock); 8973 if (!skipCall) 8974 dev_data->device_dispatch_table->CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues); 8975} 8976 8977VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 8978vkCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t slot) { 8979 VkBool32 skipCall = VK_FALSE; 8980 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 8981 loader_platform_thread_lock_mutex(&globalLock); 8982 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 8983 if (pCB) { 8984 QueryObject query = {queryPool, slot}; 8985 pCB->queryToStateMap[query] = 1; 8986 if (pCB->state == CB_RECORDING) { 8987 skipCall |= addCmd(dev_data, pCB, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()"); 8988 } else { 8989 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWriteTimestamp()"); 8990 } 8991 } 8992 loader_platform_thread_unlock_mutex(&globalLock); 8993 if (VK_FALSE == skipCall) 8994 dev_data->device_dispatch_table->CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot); 8995} 8996 8997VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo, 8998 const VkAllocationCallbacks *pAllocator, 8999 VkFramebuffer *pFramebuffer) { 9000 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 9001 VkResult result = dev_data->device_dispatch_table->CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer); 9002 if (VK_SUCCESS == result) { 9003 // Shadow create info and store in map 9004 VkFramebufferCreateInfo *localFBCI = new VkFramebufferCreateInfo(*pCreateInfo); 9005 if (pCreateInfo->pAttachments) { 9006 localFBCI->pAttachments = new VkImageView[localFBCI->attachmentCount]; 9007 memcpy((void *)localFBCI->pAttachments, pCreateInfo->pAttachments, localFBCI->attachmentCount * sizeof(VkImageView)); 9008 } 9009 FRAMEBUFFER_NODE fbNode = {}; 9010 fbNode.createInfo = *localFBCI; 9011 std::pair<VkFramebuffer, FRAMEBUFFER_NODE> fbPair(*pFramebuffer, fbNode); 9012 loader_platform_thread_lock_mutex(&globalLock); 9013#if MTMERGE 9014 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { 9015 VkImageView view = pCreateInfo->pAttachments[i]; 9016 auto view_data = dev_data->imageViewMap.find(view); 9017 if (view_data == dev_data->imageViewMap.end()) { 9018 continue; 9019 } 9020 MT_FB_ATTACHMENT_INFO fb_info; 9021 get_mem_binding_from_object(dev_data, device, (uint64_t)(view_data->second.image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 9022 &fb_info.mem); 9023 fb_info.image = view_data->second.image; 9024 dev_data->fbMap[*pFramebuffer].attachments.push_back(fb_info); 9025 } 9026#endif 9027 dev_data->frameBufferMap.insert(fbPair); 9028 loader_platform_thread_unlock_mutex(&globalLock); 9029 } 9030 return result; 9031} 9032 9033VkBool32 FindDependency(const int index, const int dependent, const std::vector<DAGNode> &subpass_to_node, 9034 std::unordered_set<uint32_t> &processed_nodes) { 9035 // If we have already checked this node we have not found a dependency path so return false. 9036 if (processed_nodes.count(index)) 9037 return VK_FALSE; 9038 processed_nodes.insert(index); 9039 const DAGNode &node = subpass_to_node[index]; 9040 // Look for a dependency path. If one exists return true else recurse on the previous nodes. 9041 if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) { 9042 for (auto elem : node.prev) { 9043 if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) 9044 return VK_TRUE; 9045 } 9046 } else { 9047 return VK_TRUE; 9048 } 9049 return VK_FALSE; 9050} 9051 9052VkBool32 CheckDependencyExists(const layer_data *my_data, const int subpass, const std::vector<uint32_t> &dependent_subpasses, 9053 const std::vector<DAGNode> &subpass_to_node, VkBool32 &skip_call) { 9054 VkBool32 result = VK_TRUE; 9055 // Loop through all subpasses that share the same attachment and make sure a dependency exists 9056 for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) { 9057 if (subpass == dependent_subpasses[k]) 9058 continue; 9059 const DAGNode &node = subpass_to_node[subpass]; 9060 // Check for a specified dependency between the two nodes. If one exists we are done. 9061 auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]); 9062 auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]); 9063 if (prev_elem == node.prev.end() && next_elem == node.next.end()) { 9064 // If no dependency exits an implicit dependency still might. If so, warn and if not throw an error. 9065 std::unordered_set<uint32_t> processed_nodes; 9066 if (FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) || 9067 FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes)) { 9068 // TODO: Verify against Valid Use section of spec 9069 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 9070 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS", 9071 "A dependency between subpasses %d and %d must exist but only an implicit one is specified.", 9072 subpass, dependent_subpasses[k]); 9073 } else { 9074 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 9075 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS", 9076 "A dependency between subpasses %d and %d must exist but one is not specified.", subpass, 9077 dependent_subpasses[k]); 9078 result = VK_FALSE; 9079 } 9080 } 9081 } 9082 return result; 9083} 9084 9085VkBool32 CheckPreserved(const layer_data *my_data, const VkRenderPassCreateInfo *pCreateInfo, const int index, 9086 const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, VkBool32 &skip_call) { 9087 const DAGNode &node = subpass_to_node[index]; 9088 // If this node writes to the attachment return true as next nodes need to preserve the attachment. 9089 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index]; 9090 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9091 if (attachment == subpass.pColorAttachments[j].attachment) 9092 return VK_TRUE; 9093 } 9094 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { 9095 if (attachment == subpass.pDepthStencilAttachment->attachment) 9096 return VK_TRUE; 9097 } 9098 VkBool32 result = VK_FALSE; 9099 // Loop through previous nodes and see if any of them write to the attachment. 9100 for (auto elem : node.prev) { 9101 result |= CheckPreserved(my_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip_call); 9102 } 9103 // If the attachment was written to by a previous node than this node needs to preserve it. 9104 if (result && depth > 0) { 9105 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index]; 9106 VkBool32 has_preserved = VK_FALSE; 9107 for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) { 9108 if (subpass.pPreserveAttachments[j] == attachment) { 9109 has_preserved = VK_TRUE; 9110 break; 9111 } 9112 } 9113 if (has_preserved == VK_FALSE) { 9114 skip_call |= 9115 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9116 DRAWSTATE_INVALID_RENDERPASS, "DS", 9117 "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index); 9118 } 9119 } 9120 return result; 9121} 9122 9123template <class T> bool isRangeOverlapping(T offset1, T size1, T offset2, T size2) { 9124 return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) || 9125 ((offset1 > offset2) && (offset1 < (offset2 + size2))); 9126} 9127 9128bool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) { 9129 return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) && 9130 isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount)); 9131} 9132 9133VkBool32 ValidateDependencies(const layer_data *my_data, const VkRenderPassBeginInfo *pRenderPassBegin, 9134 const std::vector<DAGNode> &subpass_to_node) { 9135 VkBool32 skip_call = VK_FALSE; 9136 const VkFramebufferCreateInfo *pFramebufferInfo = &my_data->frameBufferMap.at(pRenderPassBegin->framebuffer).createInfo; 9137 const VkRenderPassCreateInfo *pCreateInfo = my_data->renderPassMap.at(pRenderPassBegin->renderPass)->pCreateInfo; 9138 std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount); 9139 std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount); 9140 std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount); 9141 // Find overlapping attachments 9142 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { 9143 for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) { 9144 VkImageView viewi = pFramebufferInfo->pAttachments[i]; 9145 VkImageView viewj = pFramebufferInfo->pAttachments[j]; 9146 if (viewi == viewj) { 9147 overlapping_attachments[i].push_back(j); 9148 overlapping_attachments[j].push_back(i); 9149 continue; 9150 } 9151 auto view_data_i = my_data->imageViewMap.find(viewi); 9152 auto view_data_j = my_data->imageViewMap.find(viewj); 9153 if (view_data_i == my_data->imageViewMap.end() || view_data_j == my_data->imageViewMap.end()) { 9154 continue; 9155 } 9156 if (view_data_i->second.image == view_data_j->second.image && 9157 isRegionOverlapping(view_data_i->second.subresourceRange, view_data_j->second.subresourceRange)) { 9158 overlapping_attachments[i].push_back(j); 9159 overlapping_attachments[j].push_back(i); 9160 continue; 9161 } 9162 auto image_data_i = my_data->imageMap.find(view_data_i->second.image); 9163 auto image_data_j = my_data->imageMap.find(view_data_j->second.image); 9164 if (image_data_i == my_data->imageMap.end() || image_data_j == my_data->imageMap.end()) { 9165 continue; 9166 } 9167 if (image_data_i->second.mem == image_data_j->second.mem && 9168 isRangeOverlapping(image_data_i->second.memOffset, image_data_i->second.memSize, image_data_j->second.memOffset, 9169 image_data_j->second.memSize)) { 9170 overlapping_attachments[i].push_back(j); 9171 overlapping_attachments[j].push_back(i); 9172 } 9173 } 9174 } 9175 for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) { 9176 uint32_t attachment = i; 9177 for (auto other_attachment : overlapping_attachments[i]) { 9178 if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) { 9179 skip_call |= 9180 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9181 DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't " 9182 "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.", 9183 attachment, other_attachment); 9184 } 9185 if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) { 9186 skip_call |= 9187 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9188 DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't " 9189 "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.", 9190 other_attachment, attachment); 9191 } 9192 } 9193 } 9194 // Find for each attachment the subpasses that use them. 9195 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9196 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; 9197 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9198 uint32_t attachment = subpass.pInputAttachments[j].attachment; 9199 input_attachment_to_subpass[attachment].push_back(i); 9200 for (auto overlapping_attachment : overlapping_attachments[attachment]) { 9201 input_attachment_to_subpass[overlapping_attachment].push_back(i); 9202 } 9203 } 9204 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9205 uint32_t attachment = subpass.pColorAttachments[j].attachment; 9206 output_attachment_to_subpass[attachment].push_back(i); 9207 for (auto overlapping_attachment : overlapping_attachments[attachment]) { 9208 output_attachment_to_subpass[overlapping_attachment].push_back(i); 9209 } 9210 } 9211 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { 9212 uint32_t attachment = subpass.pDepthStencilAttachment->attachment; 9213 output_attachment_to_subpass[attachment].push_back(i); 9214 for (auto overlapping_attachment : overlapping_attachments[attachment]) { 9215 output_attachment_to_subpass[overlapping_attachment].push_back(i); 9216 } 9217 } 9218 } 9219 // If there is a dependency needed make sure one exists 9220 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9221 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; 9222 // If the attachment is an input then all subpasses that output must have a dependency relationship 9223 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9224 const uint32_t &attachment = subpass.pInputAttachments[j].attachment; 9225 CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call); 9226 } 9227 // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship 9228 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9229 const uint32_t &attachment = subpass.pColorAttachments[j].attachment; 9230 CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call); 9231 CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call); 9232 } 9233 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { 9234 const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment; 9235 CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call); 9236 CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call); 9237 } 9238 } 9239 // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was 9240 // written. 9241 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9242 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; 9243 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9244 CheckPreserved(my_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip_call); 9245 } 9246 } 9247 return skip_call; 9248} 9249 9250VkBool32 ValidateLayouts(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo) { 9251 VkBool32 skip = VK_FALSE; 9252 9253 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9254 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; 9255 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9256 if (subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && 9257 subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 9258 if (subpass.pInputAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) { 9259 // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance 9260 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 9261 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9262 "Layout for input attachment is GENERAL but should be READ_ONLY_OPTIMAL."); 9263 } else { 9264 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9265 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9266 "Layout for input attachment is %s but can only be READ_ONLY_OPTIMAL or GENERAL.", 9267 string_VkImageLayout(subpass.pInputAttachments[j].layout)); 9268 } 9269 } 9270 } 9271 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9272 if (subpass.pColorAttachments[j].layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { 9273 if (subpass.pColorAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) { 9274 // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance 9275 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 9276 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9277 "Layout for color attachment is GENERAL but should be COLOR_ATTACHMENT_OPTIMAL."); 9278 } else { 9279 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9280 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9281 "Layout for color attachment is %s but can only be COLOR_ATTACHMENT_OPTIMAL or GENERAL.", 9282 string_VkImageLayout(subpass.pColorAttachments[j].layout)); 9283 } 9284 } 9285 } 9286 if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) { 9287 if (subpass.pDepthStencilAttachment->layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { 9288 if (subpass.pDepthStencilAttachment->layout == VK_IMAGE_LAYOUT_GENERAL) { 9289 // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance 9290 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, 9291 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9292 "Layout for depth attachment is GENERAL but should be DEPTH_STENCIL_ATTACHMENT_OPTIMAL."); 9293 } else { 9294 skip |= 9295 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9296 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 9297 "Layout for depth attachment is %s but can only be DEPTH_STENCIL_ATTACHMENT_OPTIMAL or GENERAL.", 9298 string_VkImageLayout(subpass.pDepthStencilAttachment->layout)); 9299 } 9300 } 9301 } 9302 } 9303 return skip; 9304} 9305 9306VkBool32 CreatePassDAG(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, 9307 std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) { 9308 VkBool32 skip_call = VK_FALSE; 9309 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9310 DAGNode &subpass_node = subpass_to_node[i]; 9311 subpass_node.pass = i; 9312 } 9313 for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) { 9314 const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i]; 9315 if (dependency.srcSubpass > dependency.dstSubpass && dependency.srcSubpass != VK_SUBPASS_EXTERNAL && 9316 dependency.dstSubpass != VK_SUBPASS_EXTERNAL) { 9317 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9318 DRAWSTATE_INVALID_RENDERPASS, "DS", 9319 "Depedency graph must be specified such that an earlier pass cannot depend on a later pass."); 9320 } else if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL && dependency.dstSubpass == VK_SUBPASS_EXTERNAL) { 9321 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9322 DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external."); 9323 } else if (dependency.srcSubpass == dependency.dstSubpass) { 9324 has_self_dependency[dependency.srcSubpass] = true; 9325 } 9326 if (dependency.dstSubpass != VK_SUBPASS_EXTERNAL) { 9327 subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass); 9328 } 9329 if (dependency.srcSubpass != VK_SUBPASS_EXTERNAL) { 9330 subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass); 9331 } 9332 } 9333 return skip_call; 9334} 9335// TODOSC : Add intercept of vkCreateShaderModule 9336 9337VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, 9338 const VkAllocationCallbacks *pAllocator, 9339 VkShaderModule *pShaderModule) { 9340 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 9341 VkBool32 skip_call = VK_FALSE; 9342 if (!shader_is_spirv(pCreateInfo)) { 9343 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 9344 /* dev */ 0, __LINE__, SHADER_CHECKER_NON_SPIRV_SHADER, "SC", "Shader is not SPIR-V"); 9345 } 9346 9347 if (VK_FALSE != skip_call) 9348 return VK_ERROR_VALIDATION_FAILED_EXT; 9349 9350 VkResult res = my_data->device_dispatch_table->CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule); 9351 9352 if (res == VK_SUCCESS) { 9353 loader_platform_thread_lock_mutex(&globalLock); 9354 my_data->shaderModuleMap[*pShaderModule] = new shader_module(pCreateInfo); 9355 loader_platform_thread_unlock_mutex(&globalLock); 9356 } 9357 return res; 9358} 9359 9360VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, 9361 const VkAllocationCallbacks *pAllocator, 9362 VkRenderPass *pRenderPass) { 9363 VkBool32 skip_call = VK_FALSE; 9364 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 9365 loader_platform_thread_lock_mutex(&globalLock); 9366 // Create DAG 9367 std::vector<bool> has_self_dependency(pCreateInfo->subpassCount); 9368 std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount); 9369 skip_call |= CreatePassDAG(dev_data, device, pCreateInfo, subpass_to_node, has_self_dependency); 9370 // Validate 9371 skip_call |= ValidateLayouts(dev_data, device, pCreateInfo); 9372 if (VK_FALSE != skip_call) { 9373 return VK_ERROR_VALIDATION_FAILED_EXT; 9374 } 9375 loader_platform_thread_unlock_mutex(&globalLock); 9376 VkResult result = dev_data->device_dispatch_table->CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass); 9377 if (VK_SUCCESS == result) { 9378 loader_platform_thread_lock_mutex(&globalLock); 9379#if MTMERGE 9380 // MTMTODO : Merge with code from below to eliminate duplication 9381 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { 9382 VkAttachmentDescription desc = pCreateInfo->pAttachments[i]; 9383 MT_PASS_ATTACHMENT_INFO pass_info; 9384 pass_info.load_op = desc.loadOp; 9385 pass_info.store_op = desc.storeOp; 9386 pass_info.attachment = i; 9387 dev_data->passMap[*pRenderPass].attachments.push_back(pass_info); 9388 } 9389 // TODO: Maybe fill list and then copy instead of locking 9390 std::unordered_map<uint32_t, bool> &attachment_first_read = dev_data->passMap[*pRenderPass].attachment_first_read; 9391 std::unordered_map<uint32_t, VkImageLayout> &attachment_first_layout = dev_data->passMap[*pRenderPass].attachment_first_layout; 9392 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 9393 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; 9394 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9395 uint32_t attachment = subpass.pInputAttachments[j].attachment; 9396 if (attachment_first_read.count(attachment)) 9397 continue; 9398 attachment_first_read.insert(std::make_pair(attachment, true)); 9399 attachment_first_layout.insert(std::make_pair(attachment, subpass.pInputAttachments[j].layout)); 9400 } 9401 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9402 uint32_t attachment = subpass.pColorAttachments[j].attachment; 9403 if (attachment_first_read.count(attachment)) 9404 continue; 9405 attachment_first_read.insert(std::make_pair(attachment, false)); 9406 attachment_first_layout.insert(std::make_pair(attachment, subpass.pColorAttachments[j].layout)); 9407 } 9408 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { 9409 uint32_t attachment = subpass.pDepthStencilAttachment->attachment; 9410 if (attachment_first_read.count(attachment)) 9411 continue; 9412 attachment_first_read.insert(std::make_pair(attachment, false)); 9413 attachment_first_layout.insert(std::make_pair(attachment, subpass.pDepthStencilAttachment->layout)); 9414 } 9415 } 9416#endif 9417 // TODOSC : Merge in tracking of renderpass from shader_checker 9418 // Shadow create info and store in map 9419 VkRenderPassCreateInfo *localRPCI = new VkRenderPassCreateInfo(*pCreateInfo); 9420 if (pCreateInfo->pAttachments) { 9421 localRPCI->pAttachments = new VkAttachmentDescription[localRPCI->attachmentCount]; 9422 memcpy((void *)localRPCI->pAttachments, pCreateInfo->pAttachments, 9423 localRPCI->attachmentCount * sizeof(VkAttachmentDescription)); 9424 } 9425 if (pCreateInfo->pSubpasses) { 9426 localRPCI->pSubpasses = new VkSubpassDescription[localRPCI->subpassCount]; 9427 memcpy((void *)localRPCI->pSubpasses, pCreateInfo->pSubpasses, localRPCI->subpassCount * sizeof(VkSubpassDescription)); 9428 9429 for (uint32_t i = 0; i < localRPCI->subpassCount; i++) { 9430 VkSubpassDescription *subpass = (VkSubpassDescription *)&localRPCI->pSubpasses[i]; 9431 const uint32_t attachmentCount = subpass->inputAttachmentCount + 9432 subpass->colorAttachmentCount * (1 + (subpass->pResolveAttachments ? 1 : 0)) + 9433 ((subpass->pDepthStencilAttachment) ? 1 : 0) + subpass->preserveAttachmentCount; 9434 VkAttachmentReference *attachments = new VkAttachmentReference[attachmentCount]; 9435 9436 memcpy(attachments, subpass->pInputAttachments, sizeof(attachments[0]) * subpass->inputAttachmentCount); 9437 subpass->pInputAttachments = attachments; 9438 attachments += subpass->inputAttachmentCount; 9439 9440 memcpy(attachments, subpass->pColorAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount); 9441 subpass->pColorAttachments = attachments; 9442 attachments += subpass->colorAttachmentCount; 9443 9444 if (subpass->pResolveAttachments) { 9445 memcpy(attachments, subpass->pResolveAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount); 9446 subpass->pResolveAttachments = attachments; 9447 attachments += subpass->colorAttachmentCount; 9448 } 9449 9450 if (subpass->pDepthStencilAttachment) { 9451 memcpy(attachments, subpass->pDepthStencilAttachment, sizeof(attachments[0]) * 1); 9452 subpass->pDepthStencilAttachment = attachments; 9453 attachments += 1; 9454 } 9455 9456 memcpy(attachments, subpass->pPreserveAttachments, sizeof(attachments[0]) * subpass->preserveAttachmentCount); 9457 subpass->pPreserveAttachments = &attachments->attachment; 9458 } 9459 } 9460 if (pCreateInfo->pDependencies) { 9461 localRPCI->pDependencies = new VkSubpassDependency[localRPCI->dependencyCount]; 9462 memcpy((void *)localRPCI->pDependencies, pCreateInfo->pDependencies, 9463 localRPCI->dependencyCount * sizeof(VkSubpassDependency)); 9464 } 9465 dev_data->renderPassMap[*pRenderPass] = new RENDER_PASS_NODE(localRPCI); 9466 dev_data->renderPassMap[*pRenderPass]->hasSelfDependency = has_self_dependency; 9467 dev_data->renderPassMap[*pRenderPass]->subpassToNode = subpass_to_node; 9468 loader_platform_thread_unlock_mutex(&globalLock); 9469 } 9470 return result; 9471} 9472// Free the renderpass shadow 9473static void deleteRenderPasses(layer_data *my_data) { 9474 if (my_data->renderPassMap.size() <= 0) 9475 return; 9476 for (auto ii = my_data->renderPassMap.begin(); ii != my_data->renderPassMap.end(); ++ii) { 9477 const VkRenderPassCreateInfo *pRenderPassInfo = (*ii).second->pCreateInfo; 9478 delete[] pRenderPassInfo->pAttachments; 9479 if (pRenderPassInfo->pSubpasses) { 9480 for (uint32_t i = 0; i < pRenderPassInfo->subpassCount; ++i) { 9481 // Attachements are all allocated in a block, so just need to 9482 // find the first non-null one to delete 9483 if (pRenderPassInfo->pSubpasses[i].pInputAttachments) { 9484 delete[] pRenderPassInfo->pSubpasses[i].pInputAttachments; 9485 } else if (pRenderPassInfo->pSubpasses[i].pColorAttachments) { 9486 delete[] pRenderPassInfo->pSubpasses[i].pColorAttachments; 9487 } else if (pRenderPassInfo->pSubpasses[i].pResolveAttachments) { 9488 delete[] pRenderPassInfo->pSubpasses[i].pResolveAttachments; 9489 } else if (pRenderPassInfo->pSubpasses[i].pPreserveAttachments) { 9490 delete[] pRenderPassInfo->pSubpasses[i].pPreserveAttachments; 9491 } 9492 } 9493 delete[] pRenderPassInfo->pSubpasses; 9494 } 9495 delete[] pRenderPassInfo->pDependencies; 9496 delete pRenderPassInfo; 9497 delete (*ii).second; 9498 } 9499 my_data->renderPassMap.clear(); 9500} 9501 9502VkBool32 VerifyFramebufferAndRenderPassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin) { 9503 VkBool32 skip_call = VK_FALSE; 9504 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 9505 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 9506 const VkRenderPassCreateInfo *pRenderPassInfo = dev_data->renderPassMap[pRenderPassBegin->renderPass]->pCreateInfo; 9507 const VkFramebufferCreateInfo framebufferInfo = dev_data->frameBufferMap[pRenderPassBegin->framebuffer].createInfo; 9508 if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) { 9509 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9510 DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using a framebuffer " 9511 "with a different number of attachments."); 9512 } 9513 for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) { 9514 const VkImageView &image_view = framebufferInfo.pAttachments[i]; 9515 auto image_data = dev_data->imageViewMap.find(image_view); 9516 assert(image_data != dev_data->imageViewMap.end()); 9517 const VkImage &image = image_data->second.image; 9518 const VkImageSubresourceRange &subRange = image_data->second.subresourceRange; 9519 IMAGE_CMD_BUF_LAYOUT_NODE newNode = {pRenderPassInfo->pAttachments[i].initialLayout, 9520 pRenderPassInfo->pAttachments[i].initialLayout}; 9521 // TODO: Do not iterate over every possibility - consolidate where possible 9522 for (uint32_t j = 0; j < subRange.levelCount; j++) { 9523 uint32_t level = subRange.baseMipLevel + j; 9524 for (uint32_t k = 0; k < subRange.layerCount; k++) { 9525 uint32_t layer = subRange.baseArrayLayer + k; 9526 VkImageSubresource sub = {subRange.aspectMask, level, layer}; 9527 IMAGE_CMD_BUF_LAYOUT_NODE node; 9528 if (!FindLayout(pCB, image, sub, node)) { 9529 SetLayout(pCB, image, sub, newNode); 9530 continue; 9531 } 9532 if (newNode.layout != node.layout) { 9533 skip_call |= 9534 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9535 DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using attachment %i " 9536 "where the " 9537 "intial layout differs from the starting layout.", 9538 i); 9539 } 9540 } 9541 } 9542 } 9543 return skip_call; 9544} 9545 9546void TransitionSubpassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, const int subpass_index) { 9547 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 9548 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 9549 auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass); 9550 if (render_pass_data == dev_data->renderPassMap.end()) { 9551 return; 9552 } 9553 const VkRenderPassCreateInfo *pRenderPassInfo = render_pass_data->second->pCreateInfo; 9554 auto framebuffer_data = dev_data->frameBufferMap.find(pRenderPassBegin->framebuffer); 9555 if (framebuffer_data == dev_data->frameBufferMap.end()) { 9556 return; 9557 } 9558 const VkFramebufferCreateInfo framebufferInfo = framebuffer_data->second.createInfo; 9559 const VkSubpassDescription &subpass = pRenderPassInfo->pSubpasses[subpass_index]; 9560 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { 9561 const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pInputAttachments[j].attachment]; 9562 SetLayout(dev_data, pCB, image_view, subpass.pInputAttachments[j].layout); 9563 } 9564 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { 9565 const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pColorAttachments[j].attachment]; 9566 SetLayout(dev_data, pCB, image_view, subpass.pColorAttachments[j].layout); 9567 } 9568 if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) { 9569 const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pDepthStencilAttachment->attachment]; 9570 SetLayout(dev_data, pCB, image_view, subpass.pDepthStencilAttachment->layout); 9571 } 9572} 9573 9574VkBool32 validatePrimaryCommandBuffer(const layer_data *my_data, const GLOBAL_CB_NODE *pCB, const std::string &cmd_name) { 9575 VkBool32 skip_call = VK_FALSE; 9576 if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) { 9577 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9578 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", "Cannot execute command %s on a secondary command buffer.", 9579 cmd_name.c_str()); 9580 } 9581 return skip_call; 9582} 9583 9584void TransitionFinalSubpassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin) { 9585 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); 9586 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); 9587 auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass); 9588 if (render_pass_data == dev_data->renderPassMap.end()) { 9589 return; 9590 } 9591 const VkRenderPassCreateInfo *pRenderPassInfo = render_pass_data->second->pCreateInfo; 9592 auto framebuffer_data = dev_data->frameBufferMap.find(pRenderPassBegin->framebuffer); 9593 if (framebuffer_data == dev_data->frameBufferMap.end()) { 9594 return; 9595 } 9596 const VkFramebufferCreateInfo framebufferInfo = framebuffer_data->second.createInfo; 9597 for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) { 9598 const VkImageView &image_view = framebufferInfo.pAttachments[i]; 9599 SetLayout(dev_data, pCB, image_view, pRenderPassInfo->pAttachments[i].finalLayout); 9600 } 9601} 9602 9603VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 9604vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, VkSubpassContents contents) { 9605 VkBool32 skipCall = VK_FALSE; 9606 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 9607 loader_platform_thread_lock_mutex(&globalLock); 9608 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 9609 if (pCB) { 9610 if (pRenderPassBegin && pRenderPassBegin->renderPass) { 9611#if MTMERGE 9612 auto pass_data = dev_data->passMap.find(pRenderPassBegin->renderPass); 9613 if (pass_data != dev_data->passMap.end()) { 9614 MT_PASS_INFO &pass_info = pass_data->second; 9615 pass_info.fb = pRenderPassBegin->framebuffer; 9616 auto cb_data = dev_data->cbMap.find(commandBuffer); 9617 for (size_t i = 0; i < pass_info.attachments.size(); ++i) { 9618 MT_FB_ATTACHMENT_INFO &fb_info = dev_data->fbMap[pass_info.fb].attachments[i]; 9619 if (pass_info.attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) { 9620 if (cb_data != dev_data->cbMap.end()) { 9621 std::function<VkBool32()> function = [=]() { 9622 set_memory_valid(dev_data, fb_info.mem, true, fb_info.image); 9623 return VK_FALSE; 9624 }; 9625 cb_data->second.validate_functions.push_back(function); 9626 } 9627 VkImageLayout &attachment_layout = pass_info.attachment_first_layout[pass_info.attachments[i].attachment]; 9628 if (attachment_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL || 9629 attachment_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 9630 skipCall |= 9631 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 9632 VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, (uint64_t)(pRenderPassBegin->renderPass), __LINE__, 9633 MEMTRACK_INVALID_LAYOUT, "MEM", "Cannot clear attachment %d with invalid first layout %d.", 9634 pass_info.attachments[i].attachment, attachment_layout); 9635 } 9636 } else if (pass_info.attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_DONT_CARE) { 9637 if (cb_data != dev_data->cbMap.end()) { 9638 std::function<VkBool32()> function = [=]() { 9639 set_memory_valid(dev_data, fb_info.mem, false, fb_info.image); 9640 return VK_FALSE; 9641 }; 9642 cb_data->second.validate_functions.push_back(function); 9643 } 9644 } else if (pass_info.attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_LOAD) { 9645 if (cb_data != dev_data->cbMap.end()) { 9646 std::function<VkBool32()> function = [=]() { 9647 return validate_memory_is_valid(dev_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image); 9648 }; 9649 cb_data->second.validate_functions.push_back(function); 9650 } 9651 } 9652 if (pass_info.attachment_first_read[pass_info.attachments[i].attachment]) { 9653 if (cb_data != dev_data->cbMap.end()) { 9654 std::function<VkBool32()> function = [=]() { 9655 return validate_memory_is_valid(dev_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image); 9656 }; 9657 cb_data->second.validate_functions.push_back(function); 9658 } 9659 } 9660 } 9661 if (cb_data != dev_data->cbMap.end()) { 9662 cb_data->second.pass = pRenderPassBegin->renderPass; 9663 } 9664 } 9665#endif 9666 skipCall |= VerifyFramebufferAndRenderPassLayouts(commandBuffer, pRenderPassBegin); 9667 auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass); 9668 if (render_pass_data != dev_data->renderPassMap.end()) { 9669 skipCall |= ValidateDependencies(dev_data, pRenderPassBegin, render_pass_data->second->subpassToNode); 9670 } 9671 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdBeginRenderPass"); 9672 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdBeginRenderPass"); 9673 skipCall |= addCmd(dev_data, pCB, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()"); 9674 pCB->activeRenderPass = pRenderPassBegin->renderPass; 9675 // This is a shallow copy as that is all that is needed for now 9676 pCB->activeRenderPassBeginInfo = *pRenderPassBegin; 9677 pCB->activeSubpass = 0; 9678 pCB->activeSubpassContents = contents; 9679 pCB->framebuffer = pRenderPassBegin->framebuffer; 9680 // Connect this framebuffer to this cmdBuffer 9681 dev_data->frameBufferMap[pCB->framebuffer].referencingCmdBuffers.insert(pCB->commandBuffer); 9682 } else { 9683 skipCall |= 9684 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9685 DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot use a NULL RenderPass object in vkCmdBeginRenderPass()"); 9686 } 9687 } 9688 loader_platform_thread_unlock_mutex(&globalLock); 9689 if (VK_FALSE == skipCall) { 9690 dev_data->device_dispatch_table->CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents); 9691 loader_platform_thread_lock_mutex(&globalLock); 9692 // This is a shallow copy as that is all that is needed for now 9693 dev_data->renderPassBeginInfo = *pRenderPassBegin; 9694 dev_data->currentSubpass = 0; 9695 loader_platform_thread_unlock_mutex(&globalLock); 9696 } 9697} 9698 9699VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) { 9700 VkBool32 skipCall = VK_FALSE; 9701 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 9702 loader_platform_thread_lock_mutex(&globalLock); 9703 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 9704 TransitionSubpassLayouts(commandBuffer, &dev_data->renderPassBeginInfo, ++dev_data->currentSubpass); 9705 if (pCB) { 9706 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass"); 9707 skipCall |= addCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()"); 9708 pCB->activeSubpass++; 9709 pCB->activeSubpassContents = contents; 9710 TransitionSubpassLayouts(commandBuffer, &pCB->activeRenderPassBeginInfo, pCB->activeSubpass); 9711 if (pCB->lastBoundPipeline) { 9712 skipCall |= validatePipelineState(dev_data, pCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pCB->lastBoundPipeline); 9713 } 9714 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass"); 9715 } 9716 loader_platform_thread_unlock_mutex(&globalLock); 9717 if (VK_FALSE == skipCall) 9718 dev_data->device_dispatch_table->CmdNextSubpass(commandBuffer, contents); 9719} 9720 9721VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass(VkCommandBuffer commandBuffer) { 9722 VkBool32 skipCall = VK_FALSE; 9723 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 9724 loader_platform_thread_lock_mutex(&globalLock); 9725#if MTMERGE 9726 auto cb_data = dev_data->cbMap.find(commandBuffer); 9727 if (cb_data != dev_data->cbMap.end()) { 9728 auto pass_data = dev_data->passMap.find(cb_data->second.pass); 9729 if (pass_data != dev_data->passMap.end()) { 9730 MT_PASS_INFO &pass_info = pass_data->second; 9731 for (size_t i = 0; i < pass_info.attachments.size(); ++i) { 9732 MT_FB_ATTACHMENT_INFO &fb_info = dev_data->fbMap[pass_info.fb].attachments[i]; 9733 if (pass_info.attachments[i].store_op == VK_ATTACHMENT_STORE_OP_STORE) { 9734 if (cb_data != dev_data->cbMap.end()) { 9735 std::function<VkBool32()> function = [=]() { 9736 set_memory_valid(dev_data, fb_info.mem, true, fb_info.image); 9737 return VK_FALSE; 9738 }; 9739 cb_data->second.validate_functions.push_back(function); 9740 } 9741 } else if (pass_info.attachments[i].store_op == VK_ATTACHMENT_STORE_OP_DONT_CARE) { 9742 if (cb_data != dev_data->cbMap.end()) { 9743 std::function<VkBool32()> function = [=]() { 9744 set_memory_valid(dev_data, fb_info.mem, false, fb_info.image); 9745 return VK_FALSE; 9746 }; 9747 cb_data->second.validate_functions.push_back(function); 9748 } 9749 } 9750 } 9751 } 9752 } 9753#endif 9754 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 9755 TransitionFinalSubpassLayouts(commandBuffer, &dev_data->renderPassBeginInfo); 9756 if (pCB) { 9757 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass"); 9758 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass"); 9759 skipCall |= addCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()"); 9760 TransitionFinalSubpassLayouts(commandBuffer, &pCB->activeRenderPassBeginInfo); 9761 pCB->activeRenderPass = 0; 9762 pCB->activeSubpass = 0; 9763 } 9764 loader_platform_thread_unlock_mutex(&globalLock); 9765 if (VK_FALSE == skipCall) 9766 dev_data->device_dispatch_table->CmdEndRenderPass(commandBuffer); 9767} 9768 9769bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass, 9770 VkRenderPass primaryPass, uint32_t primaryAttach, uint32_t secondaryAttach, const char *msg) { 9771 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9772 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9773 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a render pass %" PRIx64 9774 " that is not compatible with the current render pass %" PRIx64 "." 9775 "Attachment %" PRIu32 " is not compatable with %" PRIu32 ". %s", 9776 (void *)secondaryBuffer, (uint64_t)(secondaryPass), (uint64_t)(primaryPass), primaryAttach, secondaryAttach, 9777 msg); 9778} 9779 9780bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass, 9781 uint32_t primaryAttach, VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass, 9782 uint32_t secondaryAttach, bool is_multi) { 9783 bool skip_call = false; 9784 auto primary_data = dev_data->renderPassMap.find(primaryPass); 9785 auto secondary_data = dev_data->renderPassMap.find(secondaryPass); 9786 if (primary_data->second->pCreateInfo->attachmentCount <= primaryAttach) { 9787 primaryAttach = VK_ATTACHMENT_UNUSED; 9788 } 9789 if (secondary_data->second->pCreateInfo->attachmentCount <= secondaryAttach) { 9790 secondaryAttach = VK_ATTACHMENT_UNUSED; 9791 } 9792 if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) { 9793 return skip_call; 9794 } 9795 if (primaryAttach == VK_ATTACHMENT_UNUSED) { 9796 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, 9797 secondaryAttach, "The first is unused while the second is not."); 9798 return skip_call; 9799 } 9800 if (secondaryAttach == VK_ATTACHMENT_UNUSED) { 9801 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, 9802 secondaryAttach, "The second is unused while the first is not."); 9803 return skip_call; 9804 } 9805 if (primary_data->second->pCreateInfo->pAttachments[primaryAttach].format != 9806 secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].format) { 9807 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, 9808 secondaryAttach, "They have different formats."); 9809 } 9810 if (primary_data->second->pCreateInfo->pAttachments[primaryAttach].samples != 9811 secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].samples) { 9812 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, 9813 secondaryAttach, "They have different samples."); 9814 } 9815 if (is_multi && 9816 primary_data->second->pCreateInfo->pAttachments[primaryAttach].flags != 9817 secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].flags) { 9818 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, 9819 secondaryAttach, "They have different flags."); 9820 } 9821 return skip_call; 9822} 9823 9824bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass, 9825 VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass, const int subpass, bool is_multi) { 9826 bool skip_call = false; 9827 auto primary_data = dev_data->renderPassMap.find(primaryPass); 9828 auto secondary_data = dev_data->renderPassMap.find(secondaryPass); 9829 const VkSubpassDescription &primary_desc = primary_data->second->pCreateInfo->pSubpasses[subpass]; 9830 const VkSubpassDescription &secondary_desc = secondary_data->second->pCreateInfo->pSubpasses[subpass]; 9831 uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount); 9832 for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) { 9833 uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED; 9834 if (i < primary_desc.inputAttachmentCount) { 9835 primary_input_attach = primary_desc.pInputAttachments[i].attachment; 9836 } 9837 if (i < secondary_desc.inputAttachmentCount) { 9838 secondary_input_attach = secondary_desc.pInputAttachments[i].attachment; 9839 } 9840 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_input_attach, secondaryBuffer, 9841 secondaryPass, secondary_input_attach, is_multi); 9842 } 9843 uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount); 9844 for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) { 9845 uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED; 9846 if (i < primary_desc.colorAttachmentCount) { 9847 primary_color_attach = primary_desc.pColorAttachments[i].attachment; 9848 } 9849 if (i < secondary_desc.colorAttachmentCount) { 9850 secondary_color_attach = secondary_desc.pColorAttachments[i].attachment; 9851 } 9852 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_color_attach, secondaryBuffer, 9853 secondaryPass, secondary_color_attach, is_multi); 9854 uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED; 9855 if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) { 9856 primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment; 9857 } 9858 if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) { 9859 secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment; 9860 } 9861 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_resolve_attach, secondaryBuffer, 9862 secondaryPass, secondary_resolve_attach, is_multi); 9863 } 9864 uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED; 9865 if (primary_desc.pDepthStencilAttachment) { 9866 primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment; 9867 } 9868 if (secondary_desc.pDepthStencilAttachment) { 9869 secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment; 9870 } 9871 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_depthstencil_attach, secondaryBuffer, 9872 secondaryPass, secondary_depthstencil_attach, is_multi); 9873 return skip_call; 9874} 9875 9876bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass, 9877 VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass) { 9878 bool skip_call = false; 9879 // Early exit if renderPass objects are identical (and therefore compatible) 9880 if (primaryPass == secondaryPass) 9881 return skip_call; 9882 auto primary_data = dev_data->renderPassMap.find(primaryPass); 9883 auto secondary_data = dev_data->renderPassMap.find(secondaryPass); 9884 if (primary_data == dev_data->renderPassMap.end() || primary_data->second == nullptr) { 9885 skip_call |= 9886 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9887 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9888 "vkCmdExecuteCommands() called w/ invalid current Cmd Buffer %p which has invalid render pass %" PRIx64 ".", 9889 (void *)primaryBuffer, (uint64_t)(primaryPass)); 9890 return skip_call; 9891 } 9892 if (secondary_data == dev_data->renderPassMap.end() || secondary_data->second == nullptr) { 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", 9896 "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer %p which has invalid render pass %" PRIx64 ".", 9897 (void *)secondaryBuffer, (uint64_t)(secondaryPass)); 9898 return skip_call; 9899 } 9900 if (primary_data->second->pCreateInfo->subpassCount != secondary_data->second->pCreateInfo->subpassCount) { 9901 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9902 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9903 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a render pass %" PRIx64 9904 " that is not compatible with the current render pass %" PRIx64 "." 9905 "They have a different number of subpasses.", 9906 (void *)secondaryBuffer, (uint64_t)(secondaryPass), (uint64_t)(primaryPass)); 9907 return skip_call; 9908 } 9909 bool is_multi = primary_data->second->pCreateInfo->subpassCount > 1; 9910 for (uint32_t i = 0; i < primary_data->second->pCreateInfo->subpassCount; ++i) { 9911 skip_call |= 9912 validateSubpassCompatibility(dev_data, primaryBuffer, primaryPass, secondaryBuffer, secondaryPass, i, is_multi); 9913 } 9914 return skip_call; 9915} 9916 9917bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB, 9918 VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) { 9919 bool skip_call = false; 9920 if (!pSubCB->beginInfo.pInheritanceInfo) { 9921 return skip_call; 9922 } 9923 VkFramebuffer primary_fb = pCB->framebuffer; 9924 VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer; 9925 if (secondary_fb != VK_NULL_HANDLE) { 9926 if (primary_fb != secondary_fb) { 9927 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9928 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9929 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a framebuffer %" PRIx64 9930 " that is not compatible with the current framebuffer %" PRIx64 ".", 9931 (void *)secondaryBuffer, (uint64_t)(secondary_fb), (uint64_t)(primary_fb)); 9932 } 9933 auto fb_data = dev_data->frameBufferMap.find(secondary_fb); 9934 if (fb_data == dev_data->frameBufferMap.end()) { 9935 skip_call |= 9936 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9937 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p " 9938 "which has invalid framebuffer %" PRIx64 ".", 9939 (void *)secondaryBuffer, (uint64_t)(secondary_fb)); 9940 return skip_call; 9941 } 9942 skip_call |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb_data->second.createInfo.renderPass, 9943 secondaryBuffer, pSubCB->beginInfo.pInheritanceInfo->renderPass); 9944 } 9945 return skip_call; 9946} 9947 9948bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) { 9949 bool skipCall = false; 9950 unordered_set<int> activeTypes; 9951 for (auto queryObject : pCB->activeQueries) { 9952 auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool); 9953 if (queryPoolData != dev_data->queryPoolMap.end()) { 9954 if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS && 9955 pSubCB->beginInfo.pInheritanceInfo) { 9956 VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics; 9957 if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) { 9958 skipCall |= log_msg( 9959 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9960 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9961 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p " 9962 "which has invalid active query pool %" PRIx64 ". Pipeline statistics is being queried so the command " 9963 "buffer must have all bits set on the queryPool.", 9964 reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first)); 9965 } 9966 } 9967 activeTypes.insert(queryPoolData->second.createInfo.queryType); 9968 } 9969 } 9970 for (auto queryObject : pSubCB->startedQueries) { 9971 auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool); 9972 if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) { 9973 skipCall |= 9974 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9975 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 9976 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p " 9977 "which has invalid active query pool %" PRIx64 "of type %d but a query of that type has been started on " 9978 "secondary Cmd Buffer %p.", 9979 reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first), 9980 queryPoolData->second.createInfo.queryType, reinterpret_cast<void *>(pSubCB->commandBuffer)); 9981 } 9982 } 9983 return skipCall; 9984} 9985 9986VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 9987vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount, const VkCommandBuffer *pCommandBuffers) { 9988 VkBool32 skipCall = VK_FALSE; 9989 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); 9990 loader_platform_thread_lock_mutex(&globalLock); 9991 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); 9992 if (pCB) { 9993 GLOBAL_CB_NODE *pSubCB = NULL; 9994 for (uint32_t i = 0; i < commandBuffersCount; i++) { 9995 pSubCB = getCBNode(dev_data, pCommandBuffers[i]); 9996 if (!pSubCB) { 9997 skipCall |= 9998 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 9999 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 10000 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p in element %u of pCommandBuffers array.", 10001 (void *)pCommandBuffers[i], i); 10002 } else if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) { 10003 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 10004 __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", 10005 "vkCmdExecuteCommands() called w/ Primary Cmd Buffer %p in element %u of pCommandBuffers " 10006 "array. All cmd buffers in pCommandBuffers array must be secondary.", 10007 (void *)pCommandBuffers[i], i); 10008 } else if (pCB->activeRenderPass) { // Secondary CB w/i RenderPass must have *CONTINUE_BIT set 10009 if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) { 10010 skipCall |= log_msg( 10011 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 10012 (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", 10013 "vkCmdExecuteCommands(): Secondary Command Buffer (%p) executed within render pass (%#" PRIxLEAST64 10014 ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set.", 10015 (void *)pCommandBuffers[i], (uint64_t)pCB->activeRenderPass); 10016 } else { 10017 // Make sure render pass is compatible with parent command buffer pass if has continue 10018 skipCall |= validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass, pCommandBuffers[i], 10019 pSubCB->beginInfo.pInheritanceInfo->renderPass); 10020 skipCall |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB); 10021 } 10022 string errorString = ""; 10023 if (!verify_renderpass_compatibility(dev_data, pCB->activeRenderPass, 10024 pSubCB->beginInfo.pInheritanceInfo->renderPass, errorString)) { 10025 skipCall |= log_msg( 10026 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 10027 (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS", 10028 "vkCmdExecuteCommands(): Secondary Command Buffer (%p) w/ render pass (%#" PRIxLEAST64 10029 ") is incompatible w/ primary command buffer (%p) w/ render pass (%#" PRIxLEAST64 ") due to: %s", 10030 (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->renderPass, (void *)commandBuffer, 10031 (uint64_t)pCB->activeRenderPass, errorString.c_str()); 10032 } 10033 // If framebuffer for secondary CB is not NULL, then it must match FB from vkCmdBeginRenderPass() 10034 // that this CB will be executed in AND framebuffer must have been created w/ RP compatible w/ renderpass 10035 if (pSubCB->beginInfo.pInheritanceInfo->framebuffer) { 10036 if (pSubCB->beginInfo.pInheritanceInfo->framebuffer != pCB->activeRenderPassBeginInfo.framebuffer) { 10037 skipCall |= log_msg( 10038 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 10039 (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_FRAMEBUFFER_INCOMPATIBLE, "DS", 10040 "vkCmdExecuteCommands(): Secondary Command Buffer (%p) references framebuffer (%#" PRIxLEAST64 10041 ") that does not match framebuffer (%#" PRIxLEAST64 ") in active renderpass (%#" PRIxLEAST64 ").", 10042 (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->framebuffer, 10043 (uint64_t)pCB->activeRenderPassBeginInfo.framebuffer, (uint64_t)pCB->activeRenderPass); 10044 } 10045 } 10046 } 10047 // TODO(mlentine): Move more logic into this method 10048 skipCall |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB); 10049 skipCall |= validateCommandBufferState(dev_data, pSubCB); 10050 // Secondary cmdBuffers are considered pending execution starting w/ 10051 // being recorded 10052 if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) { 10053 if (dev_data->globalInFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->globalInFlightCmdBuffers.end()) { 10054 skipCall |= log_msg( 10055 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 10056 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS", 10057 "Attempt to simultaneously execute CB %#" PRIxLEAST64 " w/o VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT " 10058 "set!", 10059 (uint64_t)(pCB->commandBuffer)); 10060 } 10061 if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) { 10062 // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous 10063 skipCall |= log_msg( 10064 dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 10065 (uint64_t)(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS", 10066 "vkCmdExecuteCommands(): Secondary Command Buffer (%#" PRIxLEAST64 10067 ") does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer " 10068 "(%#" PRIxLEAST64 ") to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT " 10069 "set, even though it does.", 10070 (uint64_t)(pCommandBuffers[i]), (uint64_t)(pCB->commandBuffer)); 10071 pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; 10072 } 10073 } 10074 if (!pCB->activeQueries.empty() && !dev_data->physDevProperties.features.inheritedQueries) { 10075 skipCall |= 10076 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 10077 reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", 10078 "vkCmdExecuteCommands(): Secondary Command Buffer " 10079 "(%#" PRIxLEAST64 ") cannot be submitted with a query in " 10080 "flight and inherited queries not " 10081 "supported on this device.", 10082 reinterpret_cast<uint64_t>(pCommandBuffers[i])); 10083 } 10084 pSubCB->primaryCommandBuffer = pCB->commandBuffer; 10085 pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer); 10086 dev_data->globalInFlightCmdBuffers.insert(pSubCB->commandBuffer); 10087 } 10088 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteComands"); 10089 skipCall |= addCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteComands()"); 10090 } 10091 loader_platform_thread_unlock_mutex(&globalLock); 10092 if (VK_FALSE == skipCall) 10093 dev_data->device_dispatch_table->CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers); 10094} 10095 10096VkBool32 ValidateMapImageLayouts(VkDevice device, VkDeviceMemory mem) { 10097 VkBool32 skip_call = VK_FALSE; 10098 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10099 auto mem_data = dev_data->memObjMap.find(mem); 10100 if ((mem_data != dev_data->memObjMap.end()) && (mem_data->second.image != VK_NULL_HANDLE)) { 10101 std::vector<VkImageLayout> layouts; 10102 if (FindLayouts(dev_data, mem_data->second.image, layouts)) { 10103 for (auto layout : layouts) { 10104 if (layout != VK_IMAGE_LAYOUT_PREINITIALIZED && layout != VK_IMAGE_LAYOUT_GENERAL) { 10105 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, 10106 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot map an image with layout %s. Only " 10107 "GENERAL or PREINITIALIZED are supported.", 10108 string_VkImageLayout(layout)); 10109 } 10110 } 10111 } 10112 } 10113 return skip_call; 10114} 10115 10116VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 10117vkMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags, void **ppData) { 10118 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10119 10120 VkBool32 skip_call = VK_FALSE; 10121 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10122 loader_platform_thread_lock_mutex(&globalLock); 10123#if MTMERGE 10124 DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem); 10125 if (pMemObj) { 10126 pMemObj->valid = true; 10127 if ((memProps.memoryTypes[pMemObj->allocInfo.memoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) { 10128 skip_call = 10129 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 10130 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_STATE, "MEM", 10131 "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj %#" PRIxLEAST64, (uint64_t)mem); 10132 } 10133 } 10134 skip_call |= validateMemRange(dev_data, mem, offset, size); 10135 storeMemRanges(dev_data, mem, offset, size); 10136#endif 10137 skip_call |= ValidateMapImageLayouts(device, mem); 10138 loader_platform_thread_unlock_mutex(&globalLock); 10139 10140 if (VK_FALSE == skip_call) { 10141 result = dev_data->device_dispatch_table->MapMemory(device, mem, offset, size, flags, ppData); 10142#if MTMERGE 10143 initializeAndTrackMemory(dev_data, mem, size, ppData); 10144#endif 10145 } 10146 return result; 10147} 10148 10149#if MTMERGE 10150VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(VkDevice device, VkDeviceMemory mem) { 10151 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10152 VkBool32 skipCall = VK_FALSE; 10153 10154 loader_platform_thread_lock_mutex(&globalLock); 10155 skipCall |= deleteMemRanges(my_data, mem); 10156 loader_platform_thread_unlock_mutex(&globalLock); 10157 if (VK_FALSE == skipCall) { 10158 my_data->device_dispatch_table->UnmapMemory(device, mem); 10159 } 10160} 10161 10162VkBool32 validateMemoryIsMapped(layer_data *my_data, const char *funcName, uint32_t memRangeCount, 10163 const VkMappedMemoryRange *pMemRanges) { 10164 VkBool32 skipCall = VK_FALSE; 10165 for (uint32_t i = 0; i < memRangeCount; ++i) { 10166 auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory); 10167 if (mem_element != my_data->memObjMap.end()) { 10168 if (mem_element->second.memRange.offset > pMemRanges[i].offset) { 10169 skipCall |= log_msg( 10170 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 10171 (uint64_t)pMemRanges[i].memory, __LINE__, MEMTRACK_INVALID_MAP, "MEM", 10172 "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER ") is less than Memory Object's offset " 10173 "(" PRINTF_SIZE_T_SPECIFIER ").", 10174 funcName, static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(mem_element->second.memRange.offset)); 10175 } 10176 if ((mem_element->second.memRange.size != VK_WHOLE_SIZE) && 10177 ((mem_element->second.memRange.offset + mem_element->second.memRange.size) < 10178 (pMemRanges[i].offset + pMemRanges[i].size))) { 10179 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 10180 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__, 10181 MEMTRACK_INVALID_MAP, "MEM", "%s: Flush/Invalidate upper-bound (" PRINTF_SIZE_T_SPECIFIER 10182 ") exceeds the Memory Object's upper-bound " 10183 "(" PRINTF_SIZE_T_SPECIFIER ").", 10184 funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size), 10185 static_cast<size_t>(mem_element->second.memRange.offset + mem_element->second.memRange.size)); 10186 } 10187 } 10188 } 10189 return skipCall; 10190} 10191 10192VkBool32 validateAndCopyNoncoherentMemoryToDriver(layer_data *my_data, uint32_t memRangeCount, 10193 const VkMappedMemoryRange *pMemRanges) { 10194 VkBool32 skipCall = VK_FALSE; 10195 for (uint32_t i = 0; i < memRangeCount; ++i) { 10196 auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory); 10197 if (mem_element != my_data->memObjMap.end()) { 10198 if (mem_element->second.pData) { 10199 VkDeviceSize size = mem_element->second.memRange.size; 10200 VkDeviceSize half_size = (size / 2); 10201 char *data = static_cast<char *>(mem_element->second.pData); 10202 for (auto j = 0; j < half_size; ++j) { 10203 if (data[j] != NoncoherentMemoryFillValue) { 10204 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 10205 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__, 10206 MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj %" PRIxLEAST64, 10207 (uint64_t)pMemRanges[i].memory); 10208 } 10209 } 10210 for (auto j = size + half_size; j < 2 * size; ++j) { 10211 if (data[j] != NoncoherentMemoryFillValue) { 10212 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 10213 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__, 10214 MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj %" PRIxLEAST64, 10215 (uint64_t)pMemRanges[i].memory); 10216 } 10217 } 10218 memcpy(mem_element->second.pDriverData, static_cast<void *>(data + (size_t)(half_size)), (size_t)(size)); 10219 } 10220 } 10221 } 10222 return skipCall; 10223} 10224 10225VK_LAYER_EXPORT VkResult VKAPI_CALL 10226vkFlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) { 10227 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10228 VkBool32 skipCall = VK_FALSE; 10229 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10230 10231 loader_platform_thread_lock_mutex(&globalLock); 10232 skipCall |= validateAndCopyNoncoherentMemoryToDriver(my_data, memRangeCount, pMemRanges); 10233 skipCall |= validateMemoryIsMapped(my_data, "vkFlushMappedMemoryRanges", memRangeCount, pMemRanges); 10234 loader_platform_thread_unlock_mutex(&globalLock); 10235 if (VK_FALSE == skipCall) { 10236 result = my_data->device_dispatch_table->FlushMappedMemoryRanges(device, memRangeCount, pMemRanges); 10237 } 10238 return result; 10239} 10240 10241VK_LAYER_EXPORT VkResult VKAPI_CALL 10242vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) { 10243 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10244 VkBool32 skipCall = VK_FALSE; 10245 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10246 10247 loader_platform_thread_lock_mutex(&globalLock); 10248 skipCall |= validateMemoryIsMapped(my_data, "vkInvalidateMappedMemoryRanges", memRangeCount, pMemRanges); 10249 loader_platform_thread_unlock_mutex(&globalLock); 10250 if (VK_FALSE == skipCall) { 10251 result = my_data->device_dispatch_table->InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges); 10252 } 10253 return result; 10254} 10255#endif 10256 10257VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) { 10258 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10259 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10260#if MTMERGE 10261 loader_platform_thread_lock_mutex(&globalLock); 10262 // Track objects tied to memory 10263 uint64_t image_handle = (uint64_t)(image); 10264 VkBool32 skipCall = 10265 set_mem_binding(dev_data, device, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory"); 10266 add_object_binding_info(dev_data, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, mem); 10267 { 10268 VkMemoryRequirements memRequirements; 10269 vkGetImageMemoryRequirements(device, image, &memRequirements); 10270 skipCall |= validate_buffer_image_aliasing(dev_data, image_handle, mem, memoryOffset, memRequirements, 10271 dev_data->memObjMap[mem].imageRanges, dev_data->memObjMap[mem].bufferRanges, 10272 VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); 10273 } 10274 print_mem_list(dev_data, device); 10275 loader_platform_thread_unlock_mutex(&globalLock); 10276#endif 10277 if (VK_FALSE == skipCall) { 10278 result = dev_data->device_dispatch_table->BindImageMemory(device, image, mem, memoryOffset); 10279 VkMemoryRequirements memRequirements; 10280 dev_data->device_dispatch_table->GetImageMemoryRequirements(device, image, &memRequirements); 10281 loader_platform_thread_lock_mutex(&globalLock); 10282 dev_data->memObjMap[mem].image = image; 10283 dev_data->imageMap[image].mem = mem; 10284 dev_data->imageMap[image].memOffset = memoryOffset; 10285 dev_data->imageMap[image].memSize = memRequirements.size; 10286 loader_platform_thread_unlock_mutex(&globalLock); 10287 } 10288 return result; 10289} 10290 10291VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent(VkDevice device, VkEvent event) { 10292 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10293 loader_platform_thread_lock_mutex(&globalLock); 10294 dev_data->eventMap[event].needsSignaled = false; 10295 dev_data->eventMap[event].stageMask = VK_PIPELINE_STAGE_HOST_BIT; 10296 loader_platform_thread_unlock_mutex(&globalLock); 10297 VkResult result = dev_data->device_dispatch_table->SetEvent(device, event); 10298 return result; 10299} 10300 10301VKAPI_ATTR VkResult VKAPI_CALL 10302vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence) { 10303 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); 10304 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10305 VkBool32 skip_call = VK_FALSE; 10306#if MTMERGE 10307 //MTMTODO : Merge this code with the checks below 10308 loader_platform_thread_lock_mutex(&globalLock); 10309 10310 for (uint32_t i = 0; i < bindInfoCount; i++) { 10311 const VkBindSparseInfo *bindInfo = &pBindInfo[i]; 10312 // Track objects tied to memory 10313 for (uint32_t j = 0; j < bindInfo->bufferBindCount; j++) { 10314 for (uint32_t k = 0; k < bindInfo->pBufferBinds[j].bindCount; k++) { 10315 if (set_sparse_mem_binding(dev_data, queue, bindInfo->pBufferBinds[j].pBinds[k].memory, 10316 (uint64_t)bindInfo->pBufferBinds[j].buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, 10317 "vkQueueBindSparse")) 10318 skip_call = VK_TRUE; 10319 } 10320 } 10321 for (uint32_t j = 0; j < bindInfo->imageOpaqueBindCount; j++) { 10322 for (uint32_t k = 0; k < bindInfo->pImageOpaqueBinds[j].bindCount; k++) { 10323 if (set_sparse_mem_binding(dev_data, queue, bindInfo->pImageOpaqueBinds[j].pBinds[k].memory, 10324 (uint64_t)bindInfo->pImageOpaqueBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 10325 "vkQueueBindSparse")) 10326 skip_call = VK_TRUE; 10327 } 10328 } 10329 for (uint32_t j = 0; j < bindInfo->imageBindCount; j++) { 10330 for (uint32_t k = 0; k < bindInfo->pImageBinds[j].bindCount; k++) { 10331 if (set_sparse_mem_binding(dev_data, queue, bindInfo->pImageBinds[j].pBinds[k].memory, 10332 (uint64_t)bindInfo->pImageBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 10333 "vkQueueBindSparse")) 10334 skip_call = VK_TRUE; 10335 } 10336 } 10337 // Validate semaphore state 10338 for (uint32_t i = 0; i < bindInfo->waitSemaphoreCount; i++) { 10339 VkSemaphore sem = bindInfo->pWaitSemaphores[i]; 10340 10341 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 10342 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_SIGNALLED) { 10343 skip_call = 10344 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, 10345 (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE", 10346 "vkQueueBindSparse: Semaphore must be in signaled state before passing to pWaitSemaphores"); 10347 } 10348 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_WAIT; 10349 } 10350 } 10351 for (uint32_t i = 0; i < bindInfo->signalSemaphoreCount; i++) { 10352 VkSemaphore sem = bindInfo->pSignalSemaphores[i]; 10353 10354 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 10355 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_UNSET) { 10356 skip_call = 10357 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, 10358 (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE", 10359 "vkQueueBindSparse: Semaphore must not be currently signaled or in a wait state"); 10360 } 10361 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_SIGNALLED; 10362 } 10363 } 10364 } 10365 10366 print_mem_list(dev_data, queue); 10367 loader_platform_thread_unlock_mutex(&globalLock); 10368#endif 10369 loader_platform_thread_lock_mutex(&globalLock); 10370 for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) { 10371 const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx]; 10372 for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) { 10373 if (dev_data->semaphoreMap[bindInfo.pWaitSemaphores[i]].signaled) { 10374 dev_data->semaphoreMap[bindInfo.pWaitSemaphores[i]].signaled = 0; 10375 } else { 10376 skip_call |= 10377 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 10378 __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS", 10379 "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.", 10380 (uint64_t)(queue), (uint64_t)(bindInfo.pWaitSemaphores[i])); 10381 } 10382 } 10383 for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) { 10384 dev_data->semaphoreMap[bindInfo.pSignalSemaphores[i]].signaled = 1; 10385 } 10386 } 10387 loader_platform_thread_unlock_mutex(&globalLock); 10388 10389 if (VK_FALSE == skip_call) 10390 return dev_data->device_dispatch_table->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence); 10391#if MTMERGE 10392 // Update semaphore state 10393 loader_platform_thread_lock_mutex(&globalLock); 10394 for (uint32_t bind_info_idx = 0; bind_info_idx < bindInfoCount; bind_info_idx++) { 10395 const VkBindSparseInfo *bindInfo = &pBindInfo[bind_info_idx]; 10396 for (uint32_t i = 0; i < bindInfo->waitSemaphoreCount; i++) { 10397 VkSemaphore sem = bindInfo->pWaitSemaphores[i]; 10398 10399 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 10400 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_UNSET; 10401 } 10402 } 10403 } 10404 loader_platform_thread_unlock_mutex(&globalLock); 10405#endif 10406 10407 return result; 10408} 10409 10410VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, 10411 const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) { 10412 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10413 VkResult result = dev_data->device_dispatch_table->CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore); 10414 if (result == VK_SUCCESS) { 10415 loader_platform_thread_lock_mutex(&globalLock); 10416 SEMAPHORE_NODE* sNode = &dev_data->semaphoreMap[*pSemaphore]; 10417 sNode->signaled = 0; 10418 sNode->in_use.store(0); 10419 sNode->state = MEMTRACK_SEMAPHORE_STATE_UNSET; 10420 loader_platform_thread_unlock_mutex(&globalLock); 10421 } 10422 return result; 10423} 10424 10425VKAPI_ATTR VkResult VKAPI_CALL 10426vkCreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) { 10427 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10428 VkResult result = dev_data->device_dispatch_table->CreateEvent(device, pCreateInfo, pAllocator, pEvent); 10429 if (result == VK_SUCCESS) { 10430 loader_platform_thread_lock_mutex(&globalLock); 10431 dev_data->eventMap[*pEvent].needsSignaled = false; 10432 dev_data->eventMap[*pEvent].in_use.store(0); 10433 dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0); 10434 loader_platform_thread_unlock_mutex(&globalLock); 10435 } 10436 return result; 10437} 10438 10439VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, 10440 const VkAllocationCallbacks *pAllocator, 10441 VkSwapchainKHR *pSwapchain) { 10442 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10443 VkResult result = dev_data->device_dispatch_table->CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); 10444 10445 if (VK_SUCCESS == result) { 10446 SWAPCHAIN_NODE *psc_node = new SWAPCHAIN_NODE(pCreateInfo); 10447 loader_platform_thread_lock_mutex(&globalLock); 10448 dev_data->device_extensions.swapchainMap[*pSwapchain] = psc_node; 10449 loader_platform_thread_unlock_mutex(&globalLock); 10450 } 10451 10452 return result; 10453} 10454 10455VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 10456vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) { 10457 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10458 bool skipCall = false; 10459 10460 loader_platform_thread_lock_mutex(&globalLock); 10461 auto swapchain_data = dev_data->device_extensions.swapchainMap.find(swapchain); 10462 if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) { 10463 if (swapchain_data->second->images.size() > 0) { 10464 for (auto swapchain_image : swapchain_data->second->images) { 10465 auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image); 10466 if (image_sub != dev_data->imageSubresourceMap.end()) { 10467 for (auto imgsubpair : image_sub->second) { 10468 auto image_item = dev_data->imageLayoutMap.find(imgsubpair); 10469 if (image_item != dev_data->imageLayoutMap.end()) { 10470 dev_data->imageLayoutMap.erase(image_item); 10471 } 10472 } 10473 dev_data->imageSubresourceMap.erase(image_sub); 10474 } 10475 skipCall = clear_object_binding(dev_data, device, (uint64_t)swapchain_image, 10476 VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT); 10477 dev_data->imageBindingMap.erase((uint64_t)swapchain_image); 10478 } 10479 } 10480 delete swapchain_data->second; 10481 dev_data->device_extensions.swapchainMap.erase(swapchain); 10482 } 10483 loader_platform_thread_unlock_mutex(&globalLock); 10484 if (!skipCall) 10485 dev_data->device_dispatch_table->DestroySwapchainKHR(device, swapchain, pAllocator); 10486} 10487 10488VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 10489vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount, VkImage *pSwapchainImages) { 10490 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10491 VkResult result = dev_data->device_dispatch_table->GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages); 10492 10493 if (result == VK_SUCCESS && pSwapchainImages != NULL) { 10494 // This should never happen and is checked by param checker. 10495 if (!pCount) 10496 return result; 10497 loader_platform_thread_lock_mutex(&globalLock); 10498 const size_t count = *pCount; 10499 auto swapchain_node = dev_data->device_extensions.swapchainMap[swapchain]; 10500 if (!swapchain_node->images.empty()) { 10501 // TODO : Not sure I like the memcmp here, but it works 10502 const bool mismatch = (swapchain_node->images.size() != count || 10503 memcmp(&swapchain_node->images[0], pSwapchainImages, sizeof(swapchain_node->images[0]) * count)); 10504 if (mismatch) { 10505 // TODO: Verify against Valid Usage section of extension 10506 log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, 10507 (uint64_t)swapchain, __LINE__, MEMTRACK_NONE, "SWAP_CHAIN", 10508 "vkGetSwapchainInfoKHR(%" PRIu64 10509 ", VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR) returned mismatching data", 10510 (uint64_t)(swapchain)); 10511 } 10512 } 10513 for (uint32_t i = 0; i < *pCount; ++i) { 10514 IMAGE_LAYOUT_NODE image_layout_node; 10515 image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED; 10516 image_layout_node.format = swapchain_node->createInfo.imageFormat; 10517 dev_data->imageMap[pSwapchainImages[i]].createInfo.mipLevels = 1; 10518 dev_data->imageMap[pSwapchainImages[i]].createInfo.arrayLayers = swapchain_node->createInfo.imageArrayLayers; 10519 swapchain_node->images.push_back(pSwapchainImages[i]); 10520 ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()}; 10521 dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair); 10522 dev_data->imageLayoutMap[subpair] = image_layout_node; 10523 dev_data->device_extensions.imageToSwapchainMap[pSwapchainImages[i]] = swapchain; 10524 } 10525 if (!swapchain_node->images.empty()) { 10526 for (auto image : swapchain_node->images) { 10527 // Add image object binding, then insert the new Mem Object and then bind it to created image 10528 add_object_create_info(dev_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, 10529 &swapchain_node->createInfo); 10530 } 10531 } 10532 loader_platform_thread_unlock_mutex(&globalLock); 10533 } 10534 return result; 10535} 10536 10537VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) { 10538 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); 10539 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10540 bool skip_call = false; 10541 10542 if (pPresentInfo) { 10543 loader_platform_thread_lock_mutex(&globalLock); 10544 for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) { 10545 if (dev_data->semaphoreMap[pPresentInfo->pWaitSemaphores[i]].signaled) { 10546 dev_data->semaphoreMap[pPresentInfo->pWaitSemaphores[i]].signaled = 0; 10547 } else { 10548 skip_call |= 10549 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 10550 __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS", 10551 "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.", 10552 (uint64_t)(queue), (uint64_t)(pPresentInfo->pWaitSemaphores[i])); 10553 } 10554 } 10555 VkDeviceMemory mem; 10556 for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) { 10557 auto swapchain_data = dev_data->device_extensions.swapchainMap.find(pPresentInfo->pSwapchains[i]); 10558 if (swapchain_data != dev_data->device_extensions.swapchainMap.end() && 10559 pPresentInfo->pImageIndices[i] < swapchain_data->second->images.size()) { 10560 VkImage image = swapchain_data->second->images[pPresentInfo->pImageIndices[i]]; 10561 skip_call |= 10562 get_mem_binding_from_object(dev_data, queue, (uint64_t)(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); 10563 skip_call |= validate_memory_is_valid(dev_data, mem, "vkQueuePresentKHR()", image); 10564 vector<VkImageLayout> layouts; 10565 if (FindLayouts(dev_data, image, layouts)) { 10566 for (auto layout : layouts) { 10567 if (layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { 10568 skip_call |= 10569 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, 10570 reinterpret_cast<uint64_t &>(queue), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", 10571 "Images passed to present must be in layout " 10572 "PRESENT_SOURCE_KHR but is in %s", 10573 string_VkImageLayout(layout)); 10574 } 10575 } 10576 } 10577 } 10578 } 10579 loader_platform_thread_unlock_mutex(&globalLock); 10580 } 10581 10582 if (!skip_call) 10583 result = dev_data->device_dispatch_table->QueuePresentKHR(queue, pPresentInfo); 10584#if MTMERGE 10585 loader_platform_thread_lock_mutex(&globalLock); 10586 for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; i++) { 10587 VkSemaphore sem = pPresentInfo->pWaitSemaphores[i]; 10588 if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) { 10589 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_UNSET; 10590 } 10591 } 10592 loader_platform_thread_unlock_mutex(&globalLock); 10593#endif 10594 return result; 10595} 10596 10597VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, 10598 VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) { 10599 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 10600 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; 10601 bool skipCall = false; 10602#if MTMERGE 10603 loader_platform_thread_lock_mutex(&globalLock); 10604 if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) { 10605 if (dev_data->semaphoreMap[semaphore].state != MEMTRACK_SEMAPHORE_STATE_UNSET) { 10606 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, 10607 (uint64_t)semaphore, __LINE__, MEMTRACK_NONE, "SEMAPHORE", 10608 "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state"); 10609 } 10610 dev_data->semaphoreMap[semaphore].state = MEMTRACK_SEMAPHORE_STATE_SIGNALLED; 10611 } 10612 auto fence_data = dev_data->fenceMap.find(fence); 10613 if (fence_data != dev_data->fenceMap.end()) { 10614 fence_data->second.swapchain = swapchain; 10615 } 10616 loader_platform_thread_unlock_mutex(&globalLock); 10617#endif 10618 if (!skipCall) { 10619 result = 10620 dev_data->device_dispatch_table->AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex); 10621 } 10622 loader_platform_thread_lock_mutex(&globalLock); 10623 // FIXME/TODO: Need to add some thing code the "fence" parameter 10624 dev_data->semaphoreMap[semaphore].signaled = 1; 10625 loader_platform_thread_unlock_mutex(&globalLock); 10626 return result; 10627} 10628 10629VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL 10630vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, 10631 const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) { 10632 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); 10633 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; 10634 VkResult res = pTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback); 10635 if (VK_SUCCESS == res) { 10636 loader_platform_thread_lock_mutex(&globalLock); 10637 res = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pMsgCallback); 10638 loader_platform_thread_unlock_mutex(&globalLock); 10639 } 10640 return res; 10641} 10642 10643VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, 10644 VkDebugReportCallbackEXT msgCallback, 10645 const VkAllocationCallbacks *pAllocator) { 10646 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); 10647 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; 10648 pTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator); 10649 loader_platform_thread_lock_mutex(&globalLock); 10650 layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator); 10651 loader_platform_thread_unlock_mutex(&globalLock); 10652} 10653 10654VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL 10655vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object, 10656 size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) { 10657 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); 10658 my_data->instance_dispatch_table->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, 10659 pMsg); 10660} 10661 10662VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) { 10663 if (!strcmp(funcName, "vkGetDeviceProcAddr")) 10664 return (PFN_vkVoidFunction)vkGetDeviceProcAddr; 10665 if (!strcmp(funcName, "vkDestroyDevice")) 10666 return (PFN_vkVoidFunction)vkDestroyDevice; 10667 if (!strcmp(funcName, "vkQueueSubmit")) 10668 return (PFN_vkVoidFunction)vkQueueSubmit; 10669 if (!strcmp(funcName, "vkWaitForFences")) 10670 return (PFN_vkVoidFunction)vkWaitForFences; 10671 if (!strcmp(funcName, "vkGetFenceStatus")) 10672 return (PFN_vkVoidFunction)vkGetFenceStatus; 10673 if (!strcmp(funcName, "vkQueueWaitIdle")) 10674 return (PFN_vkVoidFunction)vkQueueWaitIdle; 10675 if (!strcmp(funcName, "vkDeviceWaitIdle")) 10676 return (PFN_vkVoidFunction)vkDeviceWaitIdle; 10677 if (!strcmp(funcName, "vkGetDeviceQueue")) 10678 return (PFN_vkVoidFunction)vkGetDeviceQueue; 10679 if (!strcmp(funcName, "vkDestroyInstance")) 10680 return (PFN_vkVoidFunction)vkDestroyInstance; 10681 if (!strcmp(funcName, "vkDestroyDevice")) 10682 return (PFN_vkVoidFunction)vkDestroyDevice; 10683 if (!strcmp(funcName, "vkDestroyFence")) 10684 return (PFN_vkVoidFunction)vkDestroyFence; 10685 if (!strcmp(funcName, "vkResetFences")) 10686 return (PFN_vkVoidFunction)vkResetFences; 10687 if (!strcmp(funcName, "vkDestroySemaphore")) 10688 return (PFN_vkVoidFunction)vkDestroySemaphore; 10689 if (!strcmp(funcName, "vkDestroyEvent")) 10690 return (PFN_vkVoidFunction)vkDestroyEvent; 10691 if (!strcmp(funcName, "vkDestroyQueryPool")) 10692 return (PFN_vkVoidFunction)vkDestroyQueryPool; 10693 if (!strcmp(funcName, "vkDestroyBuffer")) 10694 return (PFN_vkVoidFunction)vkDestroyBuffer; 10695 if (!strcmp(funcName, "vkDestroyBufferView")) 10696 return (PFN_vkVoidFunction)vkDestroyBufferView; 10697 if (!strcmp(funcName, "vkDestroyImage")) 10698 return (PFN_vkVoidFunction)vkDestroyImage; 10699 if (!strcmp(funcName, "vkDestroyImageView")) 10700 return (PFN_vkVoidFunction)vkDestroyImageView; 10701 if (!strcmp(funcName, "vkDestroyShaderModule")) 10702 return (PFN_vkVoidFunction)vkDestroyShaderModule; 10703 if (!strcmp(funcName, "vkDestroyPipeline")) 10704 return (PFN_vkVoidFunction)vkDestroyPipeline; 10705 if (!strcmp(funcName, "vkDestroyPipelineLayout")) 10706 return (PFN_vkVoidFunction)vkDestroyPipelineLayout; 10707 if (!strcmp(funcName, "vkDestroySampler")) 10708 return (PFN_vkVoidFunction)vkDestroySampler; 10709 if (!strcmp(funcName, "vkDestroyDescriptorSetLayout")) 10710 return (PFN_vkVoidFunction)vkDestroyDescriptorSetLayout; 10711 if (!strcmp(funcName, "vkDestroyDescriptorPool")) 10712 return (PFN_vkVoidFunction)vkDestroyDescriptorPool; 10713 if (!strcmp(funcName, "vkDestroyFramebuffer")) 10714 return (PFN_vkVoidFunction)vkDestroyFramebuffer; 10715 if (!strcmp(funcName, "vkDestroyRenderPass")) 10716 return (PFN_vkVoidFunction)vkDestroyRenderPass; 10717 if (!strcmp(funcName, "vkCreateBuffer")) 10718 return (PFN_vkVoidFunction)vkCreateBuffer; 10719 if (!strcmp(funcName, "vkCreateBufferView")) 10720 return (PFN_vkVoidFunction)vkCreateBufferView; 10721 if (!strcmp(funcName, "vkCreateImage")) 10722 return (PFN_vkVoidFunction)vkCreateImage; 10723 if (!strcmp(funcName, "vkCreateImageView")) 10724 return (PFN_vkVoidFunction)vkCreateImageView; 10725 if (!strcmp(funcName, "vkCreateFence")) 10726 return (PFN_vkVoidFunction)vkCreateFence; 10727 if (!strcmp(funcName, "CreatePipelineCache")) 10728 return (PFN_vkVoidFunction)vkCreatePipelineCache; 10729 if (!strcmp(funcName, "DestroyPipelineCache")) 10730 return (PFN_vkVoidFunction)vkDestroyPipelineCache; 10731 if (!strcmp(funcName, "GetPipelineCacheData")) 10732 return (PFN_vkVoidFunction)vkGetPipelineCacheData; 10733 if (!strcmp(funcName, "MergePipelineCaches")) 10734 return (PFN_vkVoidFunction)vkMergePipelineCaches; 10735 if (!strcmp(funcName, "vkCreateGraphicsPipelines")) 10736 return (PFN_vkVoidFunction)vkCreateGraphicsPipelines; 10737 if (!strcmp(funcName, "vkCreateComputePipelines")) 10738 return (PFN_vkVoidFunction)vkCreateComputePipelines; 10739 if (!strcmp(funcName, "vkCreateSampler")) 10740 return (PFN_vkVoidFunction)vkCreateSampler; 10741 if (!strcmp(funcName, "vkCreateDescriptorSetLayout")) 10742 return (PFN_vkVoidFunction)vkCreateDescriptorSetLayout; 10743 if (!strcmp(funcName, "vkCreatePipelineLayout")) 10744 return (PFN_vkVoidFunction)vkCreatePipelineLayout; 10745 if (!strcmp(funcName, "vkCreateDescriptorPool")) 10746 return (PFN_vkVoidFunction)vkCreateDescriptorPool; 10747 if (!strcmp(funcName, "vkResetDescriptorPool")) 10748 return (PFN_vkVoidFunction)vkResetDescriptorPool; 10749 if (!strcmp(funcName, "vkAllocateDescriptorSets")) 10750 return (PFN_vkVoidFunction)vkAllocateDescriptorSets; 10751 if (!strcmp(funcName, "vkFreeDescriptorSets")) 10752 return (PFN_vkVoidFunction)vkFreeDescriptorSets; 10753 if (!strcmp(funcName, "vkUpdateDescriptorSets")) 10754 return (PFN_vkVoidFunction)vkUpdateDescriptorSets; 10755 if (!strcmp(funcName, "vkCreateCommandPool")) 10756 return (PFN_vkVoidFunction)vkCreateCommandPool; 10757 if (!strcmp(funcName, "vkDestroyCommandPool")) 10758 return (PFN_vkVoidFunction)vkDestroyCommandPool; 10759 if (!strcmp(funcName, "vkResetCommandPool")) 10760 return (PFN_vkVoidFunction)vkResetCommandPool; 10761 if (!strcmp(funcName, "vkCreateQueryPool")) 10762 return (PFN_vkVoidFunction)vkCreateQueryPool; 10763 if (!strcmp(funcName, "vkAllocateCommandBuffers")) 10764 return (PFN_vkVoidFunction)vkAllocateCommandBuffers; 10765 if (!strcmp(funcName, "vkFreeCommandBuffers")) 10766 return (PFN_vkVoidFunction)vkFreeCommandBuffers; 10767 if (!strcmp(funcName, "vkBeginCommandBuffer")) 10768 return (PFN_vkVoidFunction)vkBeginCommandBuffer; 10769 if (!strcmp(funcName, "vkEndCommandBuffer")) 10770 return (PFN_vkVoidFunction)vkEndCommandBuffer; 10771 if (!strcmp(funcName, "vkResetCommandBuffer")) 10772 return (PFN_vkVoidFunction)vkResetCommandBuffer; 10773 if (!strcmp(funcName, "vkCmdBindPipeline")) 10774 return (PFN_vkVoidFunction)vkCmdBindPipeline; 10775 if (!strcmp(funcName, "vkCmdSetViewport")) 10776 return (PFN_vkVoidFunction)vkCmdSetViewport; 10777 if (!strcmp(funcName, "vkCmdSetScissor")) 10778 return (PFN_vkVoidFunction)vkCmdSetScissor; 10779 if (!strcmp(funcName, "vkCmdSetLineWidth")) 10780 return (PFN_vkVoidFunction)vkCmdSetLineWidth; 10781 if (!strcmp(funcName, "vkCmdSetDepthBias")) 10782 return (PFN_vkVoidFunction)vkCmdSetDepthBias; 10783 if (!strcmp(funcName, "vkCmdSetBlendConstants")) 10784 return (PFN_vkVoidFunction)vkCmdSetBlendConstants; 10785 if (!strcmp(funcName, "vkCmdSetDepthBounds")) 10786 return (PFN_vkVoidFunction)vkCmdSetDepthBounds; 10787 if (!strcmp(funcName, "vkCmdSetStencilCompareMask")) 10788 return (PFN_vkVoidFunction)vkCmdSetStencilCompareMask; 10789 if (!strcmp(funcName, "vkCmdSetStencilWriteMask")) 10790 return (PFN_vkVoidFunction)vkCmdSetStencilWriteMask; 10791 if (!strcmp(funcName, "vkCmdSetStencilReference")) 10792 return (PFN_vkVoidFunction)vkCmdSetStencilReference; 10793 if (!strcmp(funcName, "vkCmdBindDescriptorSets")) 10794 return (PFN_vkVoidFunction)vkCmdBindDescriptorSets; 10795 if (!strcmp(funcName, "vkCmdBindVertexBuffers")) 10796 return (PFN_vkVoidFunction)vkCmdBindVertexBuffers; 10797 if (!strcmp(funcName, "vkCmdBindIndexBuffer")) 10798 return (PFN_vkVoidFunction)vkCmdBindIndexBuffer; 10799 if (!strcmp(funcName, "vkCmdDraw")) 10800 return (PFN_vkVoidFunction)vkCmdDraw; 10801 if (!strcmp(funcName, "vkCmdDrawIndexed")) 10802 return (PFN_vkVoidFunction)vkCmdDrawIndexed; 10803 if (!strcmp(funcName, "vkCmdDrawIndirect")) 10804 return (PFN_vkVoidFunction)vkCmdDrawIndirect; 10805 if (!strcmp(funcName, "vkCmdDrawIndexedIndirect")) 10806 return (PFN_vkVoidFunction)vkCmdDrawIndexedIndirect; 10807 if (!strcmp(funcName, "vkCmdDispatch")) 10808 return (PFN_vkVoidFunction)vkCmdDispatch; 10809 if (!strcmp(funcName, "vkCmdDispatchIndirect")) 10810 return (PFN_vkVoidFunction)vkCmdDispatchIndirect; 10811 if (!strcmp(funcName, "vkCmdCopyBuffer")) 10812 return (PFN_vkVoidFunction)vkCmdCopyBuffer; 10813 if (!strcmp(funcName, "vkCmdCopyImage")) 10814 return (PFN_vkVoidFunction)vkCmdCopyImage; 10815 if (!strcmp(funcName, "vkCmdBlitImage")) 10816 return (PFN_vkVoidFunction)vkCmdBlitImage; 10817 if (!strcmp(funcName, "vkCmdCopyBufferToImage")) 10818 return (PFN_vkVoidFunction)vkCmdCopyBufferToImage; 10819 if (!strcmp(funcName, "vkCmdCopyImageToBuffer")) 10820 return (PFN_vkVoidFunction)vkCmdCopyImageToBuffer; 10821 if (!strcmp(funcName, "vkCmdUpdateBuffer")) 10822 return (PFN_vkVoidFunction)vkCmdUpdateBuffer; 10823 if (!strcmp(funcName, "vkCmdFillBuffer")) 10824 return (PFN_vkVoidFunction)vkCmdFillBuffer; 10825 if (!strcmp(funcName, "vkCmdClearColorImage")) 10826 return (PFN_vkVoidFunction)vkCmdClearColorImage; 10827 if (!strcmp(funcName, "vkCmdClearDepthStencilImage")) 10828 return (PFN_vkVoidFunction)vkCmdClearDepthStencilImage; 10829 if (!strcmp(funcName, "vkCmdClearAttachments")) 10830 return (PFN_vkVoidFunction)vkCmdClearAttachments; 10831 if (!strcmp(funcName, "vkCmdResolveImage")) 10832 return (PFN_vkVoidFunction)vkCmdResolveImage; 10833 if (!strcmp(funcName, "vkCmdSetEvent")) 10834 return (PFN_vkVoidFunction)vkCmdSetEvent; 10835 if (!strcmp(funcName, "vkCmdResetEvent")) 10836 return (PFN_vkVoidFunction)vkCmdResetEvent; 10837 if (!strcmp(funcName, "vkCmdWaitEvents")) 10838 return (PFN_vkVoidFunction)vkCmdWaitEvents; 10839 if (!strcmp(funcName, "vkCmdPipelineBarrier")) 10840 return (PFN_vkVoidFunction)vkCmdPipelineBarrier; 10841 if (!strcmp(funcName, "vkCmdBeginQuery")) 10842 return (PFN_vkVoidFunction)vkCmdBeginQuery; 10843 if (!strcmp(funcName, "vkCmdEndQuery")) 10844 return (PFN_vkVoidFunction)vkCmdEndQuery; 10845 if (!strcmp(funcName, "vkCmdResetQueryPool")) 10846 return (PFN_vkVoidFunction)vkCmdResetQueryPool; 10847 if (!strcmp(funcName, "vkCmdCopyQueryPoolResults")) 10848 return (PFN_vkVoidFunction)vkCmdCopyQueryPoolResults; 10849 if (!strcmp(funcName, "vkCmdPushConstants")) 10850 return (PFN_vkVoidFunction)vkCmdPushConstants; 10851 if (!strcmp(funcName, "vkCmdWriteTimestamp")) 10852 return (PFN_vkVoidFunction)vkCmdWriteTimestamp; 10853 if (!strcmp(funcName, "vkCreateFramebuffer")) 10854 return (PFN_vkVoidFunction)vkCreateFramebuffer; 10855 if (!strcmp(funcName, "vkCreateShaderModule")) 10856 return (PFN_vkVoidFunction)vkCreateShaderModule; 10857 if (!strcmp(funcName, "vkCreateRenderPass")) 10858 return (PFN_vkVoidFunction)vkCreateRenderPass; 10859 if (!strcmp(funcName, "vkCmdBeginRenderPass")) 10860 return (PFN_vkVoidFunction)vkCmdBeginRenderPass; 10861 if (!strcmp(funcName, "vkCmdNextSubpass")) 10862 return (PFN_vkVoidFunction)vkCmdNextSubpass; 10863 if (!strcmp(funcName, "vkCmdEndRenderPass")) 10864 return (PFN_vkVoidFunction)vkCmdEndRenderPass; 10865 if (!strcmp(funcName, "vkCmdExecuteCommands")) 10866 return (PFN_vkVoidFunction)vkCmdExecuteCommands; 10867 if (!strcmp(funcName, "vkSetEvent")) 10868 return (PFN_vkVoidFunction)vkSetEvent; 10869 if (!strcmp(funcName, "vkMapMemory")) 10870 return (PFN_vkVoidFunction)vkMapMemory; 10871#if MTMERGE 10872 if (!strcmp(funcName, "vkUnmapMemory")) 10873 return (PFN_vkVoidFunction)vkUnmapMemory; 10874 if (!strcmp(funcName, "vkAllocateMemory")) 10875 return (PFN_vkVoidFunction)vkAllocateMemory; 10876 if (!strcmp(funcName, "vkFreeMemory")) 10877 return (PFN_vkVoidFunction)vkFreeMemory; 10878 if (!strcmp(funcName, "vkFlushMappedMemoryRanges")) 10879 return (PFN_vkVoidFunction)vkFlushMappedMemoryRanges; 10880 if (!strcmp(funcName, "vkInvalidateMappedMemoryRanges")) 10881 return (PFN_vkVoidFunction)vkInvalidateMappedMemoryRanges; 10882 if (!strcmp(funcName, "vkBindBufferMemory")) 10883 return (PFN_vkVoidFunction)vkBindBufferMemory; 10884 if (!strcmp(funcName, "vkGetBufferMemoryRequirements")) 10885 return (PFN_vkVoidFunction)vkGetBufferMemoryRequirements; 10886 if (!strcmp(funcName, "vkGetImageMemoryRequirements")) 10887 return (PFN_vkVoidFunction)vkGetImageMemoryRequirements; 10888#endif 10889 if (!strcmp(funcName, "vkGetQueryPoolResults")) 10890 return (PFN_vkVoidFunction)vkGetQueryPoolResults; 10891 if (!strcmp(funcName, "vkBindImageMemory")) 10892 return (PFN_vkVoidFunction)vkBindImageMemory; 10893 if (!strcmp(funcName, "vkQueueBindSparse")) 10894 return (PFN_vkVoidFunction)vkQueueBindSparse; 10895 if (!strcmp(funcName, "vkCreateSemaphore")) 10896 return (PFN_vkVoidFunction)vkCreateSemaphore; 10897 if (!strcmp(funcName, "vkCreateEvent")) 10898 return (PFN_vkVoidFunction)vkCreateEvent; 10899 10900 if (dev == NULL) 10901 return NULL; 10902 10903 layer_data *dev_data; 10904 dev_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map); 10905 10906 if (dev_data->device_extensions.wsi_enabled) { 10907 if (!strcmp(funcName, "vkCreateSwapchainKHR")) 10908 return (PFN_vkVoidFunction)vkCreateSwapchainKHR; 10909 if (!strcmp(funcName, "vkDestroySwapchainKHR")) 10910 return (PFN_vkVoidFunction)vkDestroySwapchainKHR; 10911 if (!strcmp(funcName, "vkGetSwapchainImagesKHR")) 10912 return (PFN_vkVoidFunction)vkGetSwapchainImagesKHR; 10913 if (!strcmp(funcName, "vkAcquireNextImageKHR")) 10914 return (PFN_vkVoidFunction)vkAcquireNextImageKHR; 10915 if (!strcmp(funcName, "vkQueuePresentKHR")) 10916 return (PFN_vkVoidFunction)vkQueuePresentKHR; 10917 } 10918 10919 VkLayerDispatchTable *pTable = dev_data->device_dispatch_table; 10920 { 10921 if (pTable->GetDeviceProcAddr == NULL) 10922 return NULL; 10923 return pTable->GetDeviceProcAddr(dev, funcName); 10924 } 10925} 10926 10927VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) { 10928 if (!strcmp(funcName, "vkGetInstanceProcAddr")) 10929 return (PFN_vkVoidFunction)vkGetInstanceProcAddr; 10930 if (!strcmp(funcName, "vkGetDeviceProcAddr")) 10931 return (PFN_vkVoidFunction)vkGetDeviceProcAddr; 10932 if (!strcmp(funcName, "vkCreateInstance")) 10933 return (PFN_vkVoidFunction)vkCreateInstance; 10934 if (!strcmp(funcName, "vkCreateDevice")) 10935 return (PFN_vkVoidFunction)vkCreateDevice; 10936 if (!strcmp(funcName, "vkDestroyInstance")) 10937 return (PFN_vkVoidFunction)vkDestroyInstance; 10938#if MTMERGE 10939 if (!strcmp(funcName, "vkGetPhysicalDeviceMemoryProperties")) 10940 return (PFN_vkVoidFunction)vkGetPhysicalDeviceMemoryProperties; 10941#endif 10942 if (!strcmp(funcName, "vkEnumerateInstanceLayerProperties")) 10943 return (PFN_vkVoidFunction)vkEnumerateInstanceLayerProperties; 10944 if (!strcmp(funcName, "vkEnumerateInstanceExtensionProperties")) 10945 return (PFN_vkVoidFunction)vkEnumerateInstanceExtensionProperties; 10946 if (!strcmp(funcName, "vkEnumerateDeviceLayerProperties")) 10947 return (PFN_vkVoidFunction)vkEnumerateDeviceLayerProperties; 10948 if (!strcmp(funcName, "vkEnumerateDeviceExtensionProperties")) 10949 return (PFN_vkVoidFunction)vkEnumerateDeviceExtensionProperties; 10950 10951 if (instance == NULL) 10952 return NULL; 10953 10954 PFN_vkVoidFunction fptr; 10955 10956 layer_data *my_data; 10957 my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); 10958 fptr = debug_report_get_instance_proc_addr(my_data->report_data, funcName); 10959 if (fptr) 10960 return fptr; 10961 10962 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; 10963 if (pTable->GetInstanceProcAddr == NULL) 10964 return NULL; 10965 return pTable->GetInstanceProcAddr(instance, funcName); 10966} 10967