diff options
| author | Mark Lobodzinski <mark@lunarg.com> | 2016-03-15 17:23:12 -0600 |
|---|---|---|
| committer | Mark Lobodzinski <mark@lunarg.com> | 2016-03-16 09:42:44 -0600 |
| commit | fc56a5aa75f13818c6100eac8fd661f8da928265 (patch) | |
| tree | 7f83cbdf09e2fceab4b1f49005ec8ff32d5a7bc9 | |
| parent | 6e7921e9d1b172a3893cbe578499d409bd0d368c (diff) | |
| download | usermoji-fc56a5aa75f13818c6100eac8fd661f8da928265.tar.xz | |
layers: Replace draw_state and mem_tracker with core validation
Change-Id: Ib8eb7491f6c60bc6d05da64a2311c8cfa5f88d60
| -rw-r--r-- | layers/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | layers/draw_state.cpp | 8605 | ||||
| -rw-r--r-- | layers/draw_state.h | 703 | ||||
| -rw-r--r-- | layers/linux/VkLayer_draw_state.json | 17 | ||||
| -rw-r--r-- | layers/linux/VkLayer_mem_tracker.json | 17 | ||||
| -rw-r--r-- | layers/mem_tracker.cpp | 3257 | ||||
| -rw-r--r-- | layers/mem_tracker.h | 218 | ||||
| -rw-r--r-- | layers/vk_layer_settings.txt | 10 | ||||
| -rw-r--r-- | layers/windows/VkLayer_draw_state.json | 17 | ||||
| -rw-r--r-- | layers/windows/VkLayer_mem_tracker.json | 17 | ||||
| -rw-r--r-- | loader/loader.h | 7 |
11 files changed, 3 insertions, 12871 deletions
diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt index 617e5483..710e168c 100644 --- a/layers/CMakeLists.txt +++ b/layers/CMakeLists.txt @@ -20,11 +20,8 @@ macro(run_vk_layer_xml_generate subcmd output) DEPENDS ${PROJECT_SOURCE_DIR}/vk.xml ${PROJECT_SOURCE_DIR}/generator.py ${PROJECT_SOURCE_DIR}/genvk.py ${PROJECT_SOURCE_DIR}/reg.py ) endmacro() -# TODO : Remove draw_state and mem_tracker once core_validation fully merged set(LAYER_JSON_FILES VkLayer_core_validation - VkLayer_draw_state - VkLayer_mem_tracker VkLayer_image VkLayer_object_tracker VkLayer_unique_objects @@ -148,10 +145,7 @@ if (WIN32) else() install(TARGETS layer_utils DESTINATION ${PROJECT_BINARY_DIR}/install_staging) endif() -# TODO : Remove draw_state and mem_tracker once core_validation fully merged add_vk_layer(core_validation core_validation.cpp vk_layer_table.cpp) -add_vk_layer(draw_state draw_state.cpp vk_layer_table.cpp) -add_vk_layer(mem_tracker mem_tracker.cpp vk_layer_table.cpp) add_vk_layer(device_limits device_limits.cpp vk_layer_table.cpp vk_layer_utils.cpp) add_vk_layer(image image.cpp vk_layer_table.cpp) add_vk_layer(swapchain swapchain.cpp vk_layer_table.cpp) diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp deleted file mode 100644 index f5435e4f..00000000 --- a/layers/draw_state.cpp +++ /dev/null @@ -1,8605 +0,0 @@ -/* Copyright (c) 2015-2016 The Khronos Group Inc. - * Copyright (c) 2015-2016 Valve Corporation - * Copyright (c) 2015-2016 LunarG, Inc. - * Copyright (C) 2015-2016 Google Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and/or associated documentation files (the "Materials"), to - * deal in the Materials without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Materials, and to permit persons to whom the Materials - * are furnished to do so, subject to the following conditions: - * - * The above copyright notice(s) and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE - * USE OR OTHER DEALINGS IN THE MATERIALS - * - * Author: Cody Northrop <cnorthrop@google.com> - * Author: Michael Lentine <mlentine@google.com> - * Author: Tobin Ehlis <tobine@google.com> - * Author: Chia-I Wu <olv@google.com> - * Author: Chris Forbes <chrisf@ijw.co.nz> - * Author: Mark Lobodzinski <mark@lunarg.com> - * Author: Ian Elliott <ianelliott@google.com> - */ - -// Allow use of STL min and max functions in Windows -#define NOMINMAX - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <unordered_map> -#include <unordered_set> -#include <map> -#include <string> -#include <iostream> -#include <algorithm> -#include <list> -#include <SPIRV/spirv.hpp> -#include <set> - -#include "vk_loader_platform.h" -#include "vk_dispatch_table_helper.h" -#include "vk_struct_string_helper_cpp.h" -#if defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wwrite-strings" -#endif -#if defined(__GNUC__) -#pragma GCC diagnostic warning "-Wwrite-strings" -#endif -#include "vk_struct_size_helper.h" -#include "draw_state.h" -#include "vk_layer_config.h" -#include "vk_layer_table.h" -#include "vk_layer_data.h" -#include "vk_layer_logging.h" -#include "vk_layer_extension_utils.h" -#include "vk_layer_utils.h" - -#if defined __ANDROID__ -#include <android/log.h> -#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "DS", __VA_ARGS__)) -#else -#define LOGCONSOLE(...) printf(__VA_ARGS__) -#endif - -using std::unordered_map; -using std::unordered_set; - -// Track command pools and their command buffers -struct CMD_POOL_INFO { - VkCommandPoolCreateFlags createFlags; - uint32_t queueFamilyIndex; - list<VkCommandBuffer> commandBuffers; // list container of cmd buffers allocated from this pool -}; - -struct devExts { - VkBool32 wsi_enabled; - unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> swapchainMap; - unordered_map<VkImage, VkSwapchainKHR> imageToSwapchainMap; -}; - -// fwd decls -struct shader_module; -struct render_pass; - -struct layer_data { - debug_report_data *report_data; - std::vector<VkDebugReportCallbackEXT> logging_callback; - VkLayerDispatchTable *device_dispatch_table; - VkLayerInstanceDispatchTable *instance_dispatch_table; - devExts device_extensions; - vector<VkQueue> queues; // all queues under given device - // Global set of all cmdBuffers that are inFlight on this device - unordered_set<VkCommandBuffer> globalInFlightCmdBuffers; - // Layer specific data - unordered_map<VkSampler, unique_ptr<SAMPLER_NODE>> sampleMap; - unordered_map<VkImageView, unique_ptr<VkImageViewCreateInfo>> imageViewMap; - unordered_map<VkImage, IMAGE_NODE> imageMap; - unordered_map<VkBufferView, unique_ptr<VkBufferViewCreateInfo>> bufferViewMap; - unordered_map<VkBuffer, BUFFER_NODE> bufferMap; - unordered_map<VkPipeline, PIPELINE_NODE *> pipelineMap; - unordered_map<VkCommandPool, CMD_POOL_INFO> commandPoolMap; - unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_NODE *> descriptorPoolMap; - unordered_map<VkDescriptorSet, SET_NODE *> setMap; - unordered_map<VkDescriptorSetLayout, LAYOUT_NODE *> descriptorSetLayoutMap; - unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap; - unordered_map<VkDeviceMemory, VkImage> memImageMap; - unordered_map<VkFence, FENCE_NODE> fenceMap; - unordered_map<VkQueue, QUEUE_NODE> queueMap; - unordered_map<VkEvent, EVENT_NODE> eventMap; - unordered_map<QueryObject, bool> queryToStateMap; - unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap; - unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap; - unordered_map<void *, GLOBAL_CB_NODE *> commandBufferMap; - unordered_map<VkFramebuffer, FRAMEBUFFER_NODE> frameBufferMap; - unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap; - unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap; - unordered_map<VkRenderPass, RENDER_PASS_NODE *> renderPassMap; - unordered_map<VkShaderModule, shader_module *> shaderModuleMap; - // Current render pass - VkRenderPassBeginInfo renderPassBeginInfo; - uint32_t currentSubpass; - - // Device specific data - PHYS_DEV_PROPERTIES_NODE physDevProperties; - - layer_data() : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), device_extensions(){}; -}; - -static const VkLayerProperties ds_global_layers[] = {{ - "VK_LAYER_LUNARG_draw_state", VK_API_VERSION, 1, "LunarG Validation Layer", -}}; - -template <class TCreateInfo> void ValidateLayerOrdering(const TCreateInfo &createInfo) { - bool foundLayer = false; - for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) { - if (!strcmp(createInfo.ppEnabledLayerNames[i], ds_global_layers[0].layerName)) { - foundLayer = true; - } - // This has to be logged to console as we don't have a callback at this point. - if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) { - LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.", - ds_global_layers[0].layerName); - } - } -} - -// Code imported from shader_checker -static void build_def_index(shader_module *); - -// A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words -// without the caller needing to care too much about the physical SPIRV module layout. -struct spirv_inst_iter { - std::vector<uint32_t>::const_iterator zero; - std::vector<uint32_t>::const_iterator it; - - uint32_t len() { return *it >> 16; } - uint32_t opcode() { return *it & 0x0ffffu; } - uint32_t const &word(unsigned n) { return it[n]; } - uint32_t offset() { return (uint32_t)(it - zero); } - - spirv_inst_iter() {} - - spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {} - - bool operator==(spirv_inst_iter const &other) { return it == other.it; } - - bool operator!=(spirv_inst_iter const &other) { return it != other.it; } - - spirv_inst_iter operator++(int) { /* x++ */ - spirv_inst_iter ii = *this; - it += len(); - return ii; - } - - spirv_inst_iter operator++() { /* ++x; */ - it += len(); - return *this; - } - - /* The iterator and the value are the same thing. */ - spirv_inst_iter &operator*() { return *this; } - spirv_inst_iter const &operator*() const { return *this; } -}; - -struct shader_module { - /* the spirv image itself */ - vector<uint32_t> words; - /* a mapping of <id> to the first word of its def. this is useful because walking type - * trees, constant expressions, etc requires jumping all over the instruction stream. - */ - unordered_map<unsigned, unsigned> def_index; - - shader_module(VkShaderModuleCreateInfo const *pCreateInfo) - : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)), - def_index() { - - build_def_index(this); - } - - /* expose begin() / end() to enable range-based for */ - spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); } /* first insn */ - spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); } /* just past last insn */ - /* given an offset into the module, produce an iterator there. */ - spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); } - - /* gets an iterator to the definition of an id */ - spirv_inst_iter get_def(unsigned id) const { - auto it = def_index.find(id); - if (it == def_index.end()) { - return end(); - } - return at(it->second); - } -}; - -// TODO : Do we need to guard access to layer_data_map w/ lock? -static unordered_map<void *, layer_data *> layer_data_map; - -// TODO : This can be much smarter, using separate locks for separate global data -static int globalLockInitialized = 0; -static loader_platform_thread_mutex globalLock; -#define MAX_TID 513 -static loader_platform_thread_id g_tidMapping[MAX_TID] = {0}; -static uint32_t g_maxTID = 0; - -template layer_data *get_my_data_ptr<layer_data>(void *data_key, std::unordered_map<void *, layer_data *> &data_map); - -// Map actual TID to an index value and return that index -// This keeps TIDs in range from 0-MAX_TID and simplifies compares between runs -static uint32_t getTIDIndex() { - loader_platform_thread_id tid = loader_platform_get_thread_id(); - for (uint32_t i = 0; i < g_maxTID; i++) { - if (tid == g_tidMapping[i]) - return i; - } - // Don't yet have mapping, set it and return newly set index - uint32_t retVal = (uint32_t)g_maxTID; - g_tidMapping[g_maxTID++] = tid; - assert(g_maxTID < MAX_TID); - return retVal; -} - -// Return a string representation of CMD_TYPE enum -static string cmdTypeToString(CMD_TYPE cmd) { - switch (cmd) { - case CMD_BINDPIPELINE: - return "CMD_BINDPIPELINE"; - case CMD_BINDPIPELINEDELTA: - return "CMD_BINDPIPELINEDELTA"; - case CMD_SETVIEWPORTSTATE: - return "CMD_SETVIEWPORTSTATE"; - case CMD_SETLINEWIDTHSTATE: - return "CMD_SETLINEWIDTHSTATE"; - case CMD_SETDEPTHBIASSTATE: - return "CMD_SETDEPTHBIASSTATE"; - case CMD_SETBLENDSTATE: - return "CMD_SETBLENDSTATE"; - case CMD_SETDEPTHBOUNDSSTATE: - return "CMD_SETDEPTHBOUNDSSTATE"; - case CMD_SETSTENCILREADMASKSTATE: - return "CMD_SETSTENCILREADMASKSTATE"; - case CMD_SETSTENCILWRITEMASKSTATE: - return "CMD_SETSTENCILWRITEMASKSTATE"; - case CMD_SETSTENCILREFERENCESTATE: - return "CMD_SETSTENCILREFERENCESTATE"; - case CMD_BINDDESCRIPTORSETS: - return "CMD_BINDDESCRIPTORSETS"; - case CMD_BINDINDEXBUFFER: - return "CMD_BINDINDEXBUFFER"; - case CMD_BINDVERTEXBUFFER: - return "CMD_BINDVERTEXBUFFER"; - case CMD_DRAW: - return "CMD_DRAW"; - case CMD_DRAWINDEXED: - return "CMD_DRAWINDEXED"; - case CMD_DRAWINDIRECT: - return "CMD_DRAWINDIRECT"; - case CMD_DRAWINDEXEDINDIRECT: - return "CMD_DRAWINDEXEDINDIRECT"; - case CMD_DISPATCH: - return "CMD_DISPATCH"; - case CMD_DISPATCHINDIRECT: - return "CMD_DISPATCHINDIRECT"; - case CMD_COPYBUFFER: - return "CMD_COPYBUFFER"; - case CMD_COPYIMAGE: - return "CMD_COPYIMAGE"; - case CMD_BLITIMAGE: - return "CMD_BLITIMAGE"; - case CMD_COPYBUFFERTOIMAGE: - return "CMD_COPYBUFFERTOIMAGE"; - case CMD_COPYIMAGETOBUFFER: - return "CMD_COPYIMAGETOBUFFER"; - case CMD_CLONEIMAGEDATA: - return "CMD_CLONEIMAGEDATA"; - case CMD_UPDATEBUFFER: - return "CMD_UPDATEBUFFER"; - case CMD_FILLBUFFER: - return "CMD_FILLBUFFER"; - case CMD_CLEARCOLORIMAGE: - return "CMD_CLEARCOLORIMAGE"; - case CMD_CLEARATTACHMENTS: - return "CMD_CLEARCOLORATTACHMENT"; - case CMD_CLEARDEPTHSTENCILIMAGE: - return "CMD_CLEARDEPTHSTENCILIMAGE"; - case CMD_RESOLVEIMAGE: - return "CMD_RESOLVEIMAGE"; - case CMD_SETEVENT: - return "CMD_SETEVENT"; - case CMD_RESETEVENT: - return "CMD_RESETEVENT"; - case CMD_WAITEVENTS: - return "CMD_WAITEVENTS"; - case CMD_PIPELINEBARRIER: - return "CMD_PIPELINEBARRIER"; - case CMD_BEGINQUERY: - return "CMD_BEGINQUERY"; - case CMD_ENDQUERY: - return "CMD_ENDQUERY"; - case CMD_RESETQUERYPOOL: - return "CMD_RESETQUERYPOOL"; - case CMD_COPYQUERYPOOLRESULTS: - return "CMD_COPYQUERYPOOLRESULTS"; - case CMD_WRITETIMESTAMP: - return "CMD_WRITETIMESTAMP"; - case CMD_INITATOMICCOUNTERS: - return "CMD_INITATOMICCOUNTERS"; - case CMD_LOADATOMICCOUNTERS: - return "CMD_LOADATOMICCOUNTERS"; - case CMD_SAVEATOMICCOUNTERS: - return "CMD_SAVEATOMICCOUNTERS"; - case CMD_BEGINRENDERPASS: - return "CMD_BEGINRENDERPASS"; - case CMD_ENDRENDERPASS: - return "CMD_ENDRENDERPASS"; - default: - return "UNKNOWN"; - } -} - -// SPIRV utility functions -static void build_def_index(shader_module *module) { - for (auto insn : *module) { - switch (insn.opcode()) { - /* Types */ - case spv::OpTypeVoid: - case spv::OpTypeBool: - case spv::OpTypeInt: - case spv::OpTypeFloat: - case spv::OpTypeVector: - case spv::OpTypeMatrix: - case spv::OpTypeImage: - case spv::OpTypeSampler: - case spv::OpTypeSampledImage: - case spv::OpTypeArray: - case spv::OpTypeRuntimeArray: - case spv::OpTypeStruct: - case spv::OpTypeOpaque: - case spv::OpTypePointer: - case spv::OpTypeFunction: - case spv::OpTypeEvent: - case spv::OpTypeDeviceEvent: - case spv::OpTypeReserveId: - case spv::OpTypeQueue: - case spv::OpTypePipe: - module->def_index[insn.word(1)] = insn.offset(); - break; - - /* Fixed constants */ - case spv::OpConstantTrue: - case spv::OpConstantFalse: - case spv::OpConstant: - case spv::OpConstantComposite: - case spv::OpConstantSampler: - case spv::OpConstantNull: - module->def_index[insn.word(2)] = insn.offset(); - break; - - /* Specialization constants */ - case spv::OpSpecConstantTrue: - case spv::OpSpecConstantFalse: - case spv::OpSpecConstant: - case spv::OpSpecConstantComposite: - case spv::OpSpecConstantOp: - module->def_index[insn.word(2)] = insn.offset(); - break; - - /* Variables */ - case spv::OpVariable: - module->def_index[insn.word(2)] = insn.offset(); - break; - - /* Functions */ - case spv::OpFunction: - module->def_index[insn.word(2)] = insn.offset(); - break; - - default: - /* We don't care about any other defs for now. */ - break; - } - } -} - -static spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) { - for (auto insn : *src) { - if (insn.opcode() == spv::OpEntryPoint) { - auto entrypointName = (char const *)&insn.word(3); - auto entrypointStageBits = 1u << insn.word(1); - - if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) { - return insn; - } - } - } - - return src->end(); -} - -bool shader_is_spirv(VkShaderModuleCreateInfo const *pCreateInfo) { - uint32_t *words = (uint32_t *)pCreateInfo->pCode; - size_t sizeInWords = pCreateInfo->codeSize / sizeof(uint32_t); - - /* Just validate that the header makes sense. */ - return sizeInWords >= 5 && words[0] == spv::MagicNumber && words[1] == spv::Version; -} - -static char const *storage_class_name(unsigned sc) { - switch (sc) { - case spv::StorageClassInput: - return "input"; - case spv::StorageClassOutput: - return "output"; - case spv::StorageClassUniformConstant: - return "const uniform"; - case spv::StorageClassUniform: - return "uniform"; - case spv::StorageClassWorkgroup: - return "workgroup local"; - case spv::StorageClassCrossWorkgroup: - return "workgroup global"; - case spv::StorageClassPrivate: - return "private global"; - case spv::StorageClassFunction: - return "function"; - case spv::StorageClassGeneric: - return "generic"; - case spv::StorageClassAtomicCounter: - return "atomic counter"; - case spv::StorageClassImage: - return "image"; - case spv::StorageClassPushConstant: - return "push constant"; - default: - return "unknown"; - } -} - -/* get the value of an integral constant */ -unsigned get_constant_value(shader_module const *src, unsigned id) { - auto value = src->get_def(id); - assert(value != src->end()); - - if (value.opcode() != spv::OpConstant) { - /* TODO: Either ensure that the specialization transform is already performed on a module we're - considering here, OR -- specialize on the fly now. - */ - return 1; - } - - return value.word(3); -} - -/* returns ptr to null terminator */ -static char *describe_type(char *dst, shader_module const *src, unsigned type) { - auto insn = src->get_def(type); - assert(insn != src->end()); - - switch (insn.opcode()) { - case spv::OpTypeBool: - return dst + sprintf(dst, "bool"); - case spv::OpTypeInt: - return dst + sprintf(dst, "%cint%d", insn.word(3) ? 's' : 'u', insn.word(2)); - case spv::OpTypeFloat: - return dst + sprintf(dst, "float%d", insn.word(2)); - case spv::OpTypeVector: - dst += sprintf(dst, "vec%d of ", insn.word(3)); - return describe_type(dst, src, insn.word(2)); - case spv::OpTypeMatrix: - dst += sprintf(dst, "mat%d of ", insn.word(3)); - return describe_type(dst, src, insn.word(2)); - case spv::OpTypeArray: - dst += sprintf(dst, "arr[%d] of ", get_constant_value(src, insn.word(3))); - return describe_type(dst, src, insn.word(2)); - case spv::OpTypePointer: - dst += sprintf(dst, "ptr to %s ", storage_class_name(insn.word(2))); - return describe_type(dst, src, insn.word(3)); - case spv::OpTypeStruct: { - dst += sprintf(dst, "struct of ("); - for (unsigned i = 2; i < insn.len(); i++) { - dst = describe_type(dst, src, insn.word(i)); - dst += sprintf(dst, i == insn.len() - 1 ? ")" : ", "); - } - return dst; - } - case spv::OpTypeSampler: - return dst + sprintf(dst, "sampler"); - case spv::OpTypeSampledImage: - dst += sprintf(dst, "sampler+"); - return describe_type(dst, src, insn.word(2)); - case spv::OpTypeImage: - dst += sprintf(dst, "image(dim=%u, sampled=%u)", insn.word(3), insn.word(7)); - return dst; - default: - return dst + sprintf(dst, "oddtype"); - } -} - -static bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool b_arrayed) { - /* walk two type trees together, and complain about differences */ - auto a_insn = a->get_def(a_type); - auto b_insn = b->get_def(b_type); - assert(a_insn != a->end()); - assert(b_insn != b->end()); - - if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) { - /* we probably just found the extra level of arrayness in b_type: compare the type inside it to a_type */ - return types_match(a, b, a_type, b_insn.word(2), false); - } - - if (a_insn.opcode() != b_insn.opcode()) { - return false; - } - - switch (a_insn.opcode()) { - /* if b_arrayed and we hit a leaf type, then we can't match -- there's nowhere for the extra OpTypeArray to be! */ - case spv::OpTypeBool: - return true && !b_arrayed; - case spv::OpTypeInt: - /* match on width, signedness */ - return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3) && !b_arrayed; - case spv::OpTypeFloat: - /* match on width */ - return a_insn.word(2) == b_insn.word(2) && !b_arrayed; - case spv::OpTypeVector: - case spv::OpTypeMatrix: - /* match on element type, count. these all have the same layout. we don't get here if - * b_arrayed -- that is handled above. */ - 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); - case spv::OpTypeArray: - /* match on element type, count. these all have the same layout. we don't get here if - * b_arrayed. This differs from vector & matrix types in that the array size is the id of a constant instruction, - * not a literal within OpTypeArray */ - return !b_arrayed && types_match(a, b, a_insn.word(2), b_insn.word(2), b_arrayed) && - get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3)); - case spv::OpTypeStruct: - /* match on all element types */ - { - if (b_arrayed) { - /* for the purposes of matching different levels of arrayness, structs are leaves. */ - return false; - } - - if (a_insn.len() != b_insn.len()) { - return false; /* structs cannot match if member counts differ */ - } - - for (unsigned i = 2; i < a_insn.len(); i++) { - if (!types_match(a, b, a_insn.word(i), b_insn.word(i), b_arrayed)) { - return false; - } - } - - return true; - } - case spv::OpTypePointer: - /* match on pointee type. storage class is expected to differ */ - return types_match(a, b, a_insn.word(3), b_insn.word(3), b_arrayed); - - default: - /* remaining types are CLisms, or may not appear in the interfaces we - * are interested in. Just claim no match. - */ - return false; - } -} - -static int value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def) { - auto it = map.find(id); - if (it == map.end()) - return def; - else - return it->second; -} - -static unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) { - auto insn = src->get_def(type); - assert(insn != src->end()); - - switch (insn.opcode()) { - case spv::OpTypePointer: - /* see through the ptr -- this is only ever at the toplevel for graphics shaders; - * we're never actually passing pointers around. */ - return get_locations_consumed_by_type(src, insn.word(3), strip_array_level); - case spv::OpTypeArray: - if (strip_array_level) { - return get_locations_consumed_by_type(src, insn.word(2), false); - } else { - return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false); - } - case spv::OpTypeMatrix: - /* num locations is the dimension * element size */ - return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false); - default: - /* everything else is just 1. */ - return 1; - - /* TODO: extend to handle 64bit scalar types, whose vectors may need - * multiple locations. */ - } -} - -typedef std::pair<unsigned, unsigned> location_t; -typedef std::pair<unsigned, unsigned> descriptor_slot_t; - -struct interface_var { - uint32_t id; - uint32_t type_id; - uint32_t offset; - /* TODO: collect the name, too? Isn't required to be present. */ -}; - -static spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) { - while (true) { - - if (def.opcode() == spv::OpTypePointer) { - def = src->get_def(def.word(3)); - } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) { - def = src->get_def(def.word(2)); - is_array_of_verts = false; - } else if (def.opcode() == spv::OpTypeStruct) { - return def; - } else { - return src->end(); - } - } -} - -static void collect_interface_block_members(layer_data *my_data, VkDevice dev, shader_module const *src, - std::map<location_t, interface_var> &out, - std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts, - uint32_t id, uint32_t type_id) { - /* Walk down the type_id presented, trying to determine whether it's actually an interface block. */ - auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts); - if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) { - /* this isn't an interface block. */ - return; - } - - std::unordered_map<unsigned, unsigned> member_components; - - /* Walk all the OpMemberDecorate for type's result id -- first pass, collect components. */ - for (auto insn : *src) { - if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) { - unsigned member_index = insn.word(2); - - if (insn.word(3) == spv::DecorationComponent) { - unsigned component = insn.word(4); - member_components[member_index] = component; - } - } - } - - /* Second pass -- produce the output, from Location decorations */ - for (auto insn : *src) { - if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) { - unsigned member_index = insn.word(2); - unsigned member_type_id = type.word(2 + member_index); - - if (insn.word(3) == spv::DecorationLocation) { - unsigned location = insn.word(4); - unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false); - auto component_it = member_components.find(member_index); - unsigned component = component_it == member_components.end() ? 0 : component_it->second; - - for (unsigned int offset = 0; offset < num_locations; offset++) { - interface_var v; - v.id = id; - /* TODO: member index in interface_var too? */ - v.type_id = member_type_id; - v.offset = offset; - out[std::make_pair(location + offset, component)] = v; - } - } - } - } -} - -static void collect_interface_by_location(layer_data *my_data, VkDevice dev, shader_module const *src, spirv_inst_iter entrypoint, - spv::StorageClass sinterface, std::map<location_t, interface_var> &out, - bool is_array_of_verts) { - std::unordered_map<unsigned, unsigned> var_locations; - std::unordered_map<unsigned, unsigned> var_builtins; - std::unordered_map<unsigned, unsigned> var_components; - std::unordered_map<unsigned, unsigned> blocks; - - for (auto insn : *src) { - - /* We consider two interface models: SSO rendezvous-by-location, and - * builtins. Complain about anything that fits neither model. - */ - if (insn.opcode() == spv::OpDecorate) { - if (insn.word(2) == spv::DecorationLocation) { - var_locations[insn.word(1)] = insn.word(3); - } - - if (insn.word(2) == spv::DecorationBuiltIn) { - var_builtins[insn.word(1)] = insn.word(3); - } - - if (insn.word(2) == spv::DecorationComponent) { - var_components[insn.word(1)] = insn.word(3); - } - - if (insn.word(2) == spv::DecorationBlock) { - blocks[insn.word(1)] = 1; - } - } - } - - /* TODO: handle grouped decorations */ - /* TODO: handle index=1 dual source outputs from FS -- two vars will - * have the same location, and we DONT want to clobber. */ - - /* find the end of the entrypoint's name string. additional zero bytes follow the actual null - terminator, to fill out the rest of the word - so we only need to look at the last byte in - the word to determine which word contains the terminator. */ - auto word = 3; - while (entrypoint.word(word) & 0xff000000u) { - ++word; - } - ++word; - - for (; word < entrypoint.len(); word++) { - auto insn = src->get_def(entrypoint.word(word)); - assert(insn != src->end()); - assert(insn.opcode() == spv::OpVariable); - - if (insn.word(3) == sinterface) { - unsigned id = insn.word(2); - unsigned type = insn.word(1); - - int location = value_or_default(var_locations, id, -1); - int builtin = value_or_default(var_builtins, id, -1); - unsigned component = value_or_default(var_components, id, 0); /* unspecified is OK, is 0 */ - - /* All variables and interface block members in the Input or Output storage classes - * must be decorated with either a builtin or an explicit location. - * - * TODO: integrate the interface block support here. For now, don't complain -- - * a valid SPIRV module will only hit this path for the interface block case, as the - * individual members of the type are decorated, rather than variable declarations. - */ - - if (location != -1) { - /* A user-defined interface variable, with a location. Where a variable - * occupied multiple locations, emit one result for each. */ - unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts); - for (unsigned int offset = 0; offset < num_locations; offset++) { - interface_var v; - v.id = id; - v.type_id = type; - v.offset = offset; - out[std::make_pair(location + offset, component)] = v; - } - } else if (builtin == -1) { - /* An interface block instance */ - collect_interface_block_members(my_data, dev, src, out, blocks, is_array_of_verts, id, type); - } - } - } -} - -static void collect_interface_by_descriptor_slot(layer_data *my_data, VkDevice dev, shader_module const *src, - std::unordered_set<uint32_t> const &accessible_ids, - std::map<descriptor_slot_t, interface_var> &out) { - - std::unordered_map<unsigned, unsigned> var_sets; - std::unordered_map<unsigned, unsigned> var_bindings; - - for (auto insn : *src) { - /* All variables in the Uniform or UniformConstant storage classes are required to be decorated with both - * DecorationDescriptorSet and DecorationBinding. - */ - if (insn.opcode() == spv::OpDecorate) { - if (insn.word(2) == spv::DecorationDescriptorSet) { - var_sets[insn.word(1)] = insn.word(3); - } - - if (insn.word(2) == spv::DecorationBinding) { - var_bindings[insn.word(1)] = insn.word(3); - } - } - } - - for (auto id : accessible_ids) { - auto insn = src->get_def(id); - assert(insn != src->end()); - - if (insn.opcode() == spv::OpVariable && - (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) { - unsigned set = value_or_default(var_sets, insn.word(2), 0); - unsigned binding = value_or_default(var_bindings, insn.word(2), 0); - - auto existing_it = out.find(std::make_pair(set, binding)); - if (existing_it != out.end()) { - /* conflict within spv image */ - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, - __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC", - "var %d (type %d) in %s interface in descriptor slot (%u,%u) conflicts with existing definition", - insn.word(2), insn.word(1), storage_class_name(insn.word(3)), existing_it->first.first, - existing_it->first.second); - } - - interface_var v; - v.id = insn.word(2); - v.type_id = insn.word(1); - out[std::make_pair(set, binding)] = v; - } - } -} - -static bool validate_interface_between_stages(layer_data *my_data, VkDevice dev, shader_module const *producer, - spirv_inst_iter producer_entrypoint, char const *producer_name, - shader_module const *consumer, spirv_inst_iter consumer_entrypoint, - char const *consumer_name, bool consumer_arrayed_input) { - std::map<location_t, interface_var> outputs; - std::map<location_t, interface_var> inputs; - - bool pass = true; - - collect_interface_by_location(my_data, dev, producer, producer_entrypoint, spv::StorageClassOutput, outputs, false); - collect_interface_by_location(my_data, dev, consumer, consumer_entrypoint, spv::StorageClassInput, inputs, - consumer_arrayed_input); - - auto a_it = outputs.begin(); - auto b_it = inputs.begin(); - - /* maps sorted by key (location); walk them together to find mismatches */ - while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) { - bool a_at_end = outputs.size() == 0 || a_it == outputs.end(); - bool b_at_end = inputs.size() == 0 || b_it == inputs.end(); - auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first; - auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first; - - if (b_at_end || ((!a_at_end) && (a_first < b_first))) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - /*dev*/ 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", - "%s writes to output location %u.%u which is not consumed by %s", producer_name, a_first.first, - a_first.second, consumer_name)) { - pass = false; - } - a_it++; - } else if (a_at_end || a_first > b_first) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, - __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", - "%s consumes input location %u.%u which is not written by %s", consumer_name, b_first.first, b_first.second, - producer_name)) { - pass = false; - } - b_it++; - } else { - if (types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id, consumer_arrayed_input)) { - /* OK! */ - } else { - char producer_type[1024]; - char consumer_type[1024]; - describe_type(producer_type, producer, a_it->second.type_id); - describe_type(consumer_type, consumer, b_it->second.type_id); - - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, - __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'", - a_first.first, a_first.second, producer_type, consumer_type)) { - pass = false; - } - } - a_it++; - b_it++; - } - } - - return pass; -} - -enum FORMAT_TYPE { - FORMAT_TYPE_UNDEFINED, - FORMAT_TYPE_FLOAT, /* UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader */ - FORMAT_TYPE_SINT, - FORMAT_TYPE_UINT, -}; - -static unsigned get_format_type(VkFormat fmt) { - switch (fmt) { - case VK_FORMAT_UNDEFINED: - return FORMAT_TYPE_UNDEFINED; - case VK_FORMAT_R8_SINT: - case VK_FORMAT_R8G8_SINT: - case VK_FORMAT_R8G8B8_SINT: - case VK_FORMAT_R8G8B8A8_SINT: - case VK_FORMAT_R16_SINT: - case VK_FORMAT_R16G16_SINT: - case VK_FORMAT_R16G16B16_SINT: - case VK_FORMAT_R16G16B16A16_SINT: - case VK_FORMAT_R32_SINT: - case VK_FORMAT_R32G32_SINT: - case VK_FORMAT_R32G32B32_SINT: - case VK_FORMAT_R32G32B32A32_SINT: - case VK_FORMAT_B8G8R8_SINT: - case VK_FORMAT_B8G8R8A8_SINT: - case VK_FORMAT_A2B10G10R10_SINT_PACK32: - case VK_FORMAT_A2R10G10B10_SINT_PACK32: - return FORMAT_TYPE_SINT; - case VK_FORMAT_R8_UINT: - case VK_FORMAT_R8G8_UINT: - case VK_FORMAT_R8G8B8_UINT: - case VK_FORMAT_R8G8B8A8_UINT: - case VK_FORMAT_R16_UINT: - case VK_FORMAT_R16G16_UINT: - case VK_FORMAT_R16G16B16_UINT: - case VK_FORMAT_R16G16B16A16_UINT: - case VK_FORMAT_R32_UINT: - case VK_FORMAT_R32G32_UINT: - case VK_FORMAT_R32G32B32_UINT: - case VK_FORMAT_R32G32B32A32_UINT: - case VK_FORMAT_B8G8R8_UINT: - case VK_FORMAT_B8G8R8A8_UINT: - case VK_FORMAT_A2B10G10R10_UINT_PACK32: - case VK_FORMAT_A2R10G10B10_UINT_PACK32: - return FORMAT_TYPE_UINT; - default: - return FORMAT_TYPE_FLOAT; - } -} - -/* characterizes a SPIR-V type appearing in an interface to a FF stage, - * for comparison to a VkFormat's characterization above. */ -static unsigned get_fundamental_type(shader_module const *src, unsigned type) { - auto insn = src->get_def(type); - assert(insn != src->end()); - - switch (insn.opcode()) { - case spv::OpTypeInt: - return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT; - case spv::OpTypeFloat: - return FORMAT_TYPE_FLOAT; - case spv::OpTypeVector: - return get_fundamental_type(src, insn.word(2)); - case spv::OpTypeMatrix: - return get_fundamental_type(src, insn.word(2)); - case spv::OpTypeArray: - return get_fundamental_type(src, insn.word(2)); - case spv::OpTypePointer: - return get_fundamental_type(src, insn.word(3)); - default: - return FORMAT_TYPE_UNDEFINED; - } -} - -static uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) { - uint32_t bit_pos = u_ffs(stage); - return bit_pos - 1; -} - -static bool validate_vi_consistency(layer_data *my_data, VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi) { - /* walk the binding descriptions, which describe the step rate and stride of each vertex buffer. - * each binding should be specified only once. - */ - std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings; - bool pass = true; - - for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) { - auto desc = &vi->pVertexBindingDescriptions[i]; - auto &binding = bindings[desc->binding]; - if (binding) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, - __LINE__, SHADER_CHECKER_INCONSISTENT_VI, "SC", - "Duplicate vertex input binding descriptions for binding %d", desc->binding)) { - pass = false; - } - } else { - binding = desc; - } - } - - return pass; -} - -static bool validate_vi_against_vs_inputs(layer_data *my_data, VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi, - shader_module const *vs, spirv_inst_iter entrypoint) { - std::map<location_t, interface_var> inputs; - bool pass = true; - - collect_interface_by_location(my_data, dev, vs, entrypoint, spv::StorageClassInput, inputs, false); - - /* Build index by location */ - std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs; - if (vi) { - for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) - attribs[vi->pVertexAttributeDescriptions[i].location] = &vi->pVertexAttributeDescriptions[i]; - } - - auto it_a = attribs.begin(); - auto it_b = inputs.begin(); - - while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) { - bool a_at_end = attribs.size() == 0 || it_a == attribs.end(); - bool b_at_end = inputs.size() == 0 || it_b == inputs.end(); - auto a_first = a_at_end ? 0 : it_a->first; - auto b_first = b_at_end ? 0 : it_b->first.first; - if (!a_at_end && (b_at_end || a_first < b_first)) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - /*dev*/ 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", - "Vertex attribute at location %d not consumed by VS", a_first)) { - pass = false; - } - it_a++; - } else if (!b_at_end && (a_at_end || b_first < a_first)) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, - __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "VS consumes input at location %d but not provided", - b_first)) { - pass = false; - } - it_b++; - } else { - unsigned attrib_type = get_format_type(it_a->second->format); - unsigned input_type = get_fundamental_type(vs, it_b->second.type_id); - - /* type checking */ - if (attrib_type != FORMAT_TYPE_UNDEFINED && input_type != FORMAT_TYPE_UNDEFINED && attrib_type != input_type) { - char vs_type[1024]; - describe_type(vs_type, vs, it_b->second.type_id); - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, - __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", - "Attribute type of `%s` at location %d does not match VS input type of `%s`", - string_VkFormat(it_a->second->format), a_first, vs_type)) { - pass = false; - } - } - - /* OK! */ - it_a++; - it_b++; - } - } - - return pass; -} - -static bool validate_fs_outputs_against_render_pass(layer_data *my_data, VkDevice dev, shader_module const *fs, - spirv_inst_iter entrypoint, RENDER_PASS_NODE const *rp, uint32_t subpass) { - const std::vector<VkFormat> &color_formats = rp->subpassColorFormats[subpass]; - std::map<location_t, interface_var> outputs; - bool pass = true; - - /* TODO: dual source blend index (spv::DecIndex, zero if not provided) */ - - collect_interface_by_location(my_data, dev, fs, entrypoint, spv::StorageClassOutput, outputs, false); - - auto it = outputs.begin(); - uint32_t attachment = 0; - - /* Walk attachment list and outputs together -- this is a little overpowered since attachments - * are currently dense, but the parallel with matching between shader stages is nice. - */ - - while ((outputs.size() > 0 && it != outputs.end()) || attachment < color_formats.size()) { - if (attachment == color_formats.size() || (it != outputs.end() && it->first.first < attachment)) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, - __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", - "FS writes to output location %d with no matching attachment", it->first.first)) { - pass = false; - } - it++; - } else if (it == outputs.end() || it->first.first > attachment) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, - __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by FS", attachment)) { - pass = false; - } - attachment++; - } else { - unsigned output_type = get_fundamental_type(fs, it->second.type_id); - unsigned att_type = get_format_type(color_formats[attachment]); - - /* type checking */ - if (att_type != FORMAT_TYPE_UNDEFINED && output_type != FORMAT_TYPE_UNDEFINED && att_type != output_type) { - char fs_type[1024]; - describe_type(fs_type, fs, it->second.type_id); - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0, - __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", - "Attachment %d of type `%s` does not match FS output type of `%s`", attachment, - string_VkFormat(color_formats[attachment]), fs_type)) { - pass = false; - } - } - - /* OK! */ - it++; - attachment++; - } - } - - return pass; -} - -/* For some analyses, we need to know about all ids referenced by the static call tree of a particular - * entrypoint. This is important for identifying the set of shader resources actually used by an entrypoint, - * for example. - * Note: we only explore parts of the image which might actually contain ids we care about for the above analyses. - * - NOT the shader input/output interfaces. - * - * TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth - * converting parts of this to be generated from the machine-readable spec instead. - */ -static void mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint, std::unordered_set<uint32_t> &ids) { - std::unordered_set<uint32_t> worklist; - worklist.insert(entrypoint.word(2)); - - while (!worklist.empty()) { - auto id_iter = worklist.begin(); - auto id = *id_iter; - worklist.erase(id_iter); - - auto insn = src->get_def(id); - if (insn == src->end()) { - /* id is something we didnt collect in build_def_index. that's OK -- we'll stumble - * across all kinds of things here that we may not care about. */ - continue; - } - - /* try to add to the output set */ - if (!ids.insert(id).second) { - continue; /* if we already saw this id, we don't want to walk it again. */ - } - - switch (insn.opcode()) { - case spv::OpFunction: - /* scan whole body of the function, enlisting anything interesting */ - while (++insn, insn.opcode() != spv::OpFunctionEnd) { - switch (insn.opcode()) { - case spv::OpLoad: - case spv::OpAtomicLoad: - case spv::OpAtomicExchange: - case spv::OpAtomicCompareExchange: - case spv::OpAtomicCompareExchangeWeak: - case spv::OpAtomicIIncrement: - case spv::OpAtomicIDecrement: - case spv::OpAtomicIAdd: - case spv::OpAtomicISub: - case spv::OpAtomicSMin: - case spv::OpAtomicUMin: - case spv::OpAtomicSMax: - case spv::OpAtomicUMax: - case spv::OpAtomicAnd: - case spv::OpAtomicOr: - case spv::OpAtomicXor: - worklist.insert(insn.word(3)); /* ptr */ - break; - case spv::OpStore: - case spv::OpAtomicStore: - worklist.insert(insn.word(1)); /* ptr */ - break; - case spv::OpAccessChain: - case spv::OpInBoundsAccessChain: - worklist.insert(insn.word(3)); /* base ptr */ - break; - case spv::OpSampledImage: - case spv::OpImageSampleImplicitLod: - case spv::OpImageSampleExplicitLod: - case spv::OpImageSampleDrefImplicitLod: - case spv::OpImageSampleDrefExplicitLod: - case spv::OpImageSampleProjImplicitLod: - case spv::OpImageSampleProjExplicitLod: - case spv::OpImageSampleProjDrefImplicitLod: - case spv::OpImageSampleProjDrefExplicitLod: - case spv::OpImageFetch: - case spv::OpImageGather: - case spv::OpImageDrefGather: - case spv::OpImageRead: - case spv::OpImage: - case spv::OpImageQueryFormat: - case spv::OpImageQueryOrder: - case spv::OpImageQuerySizeLod: - case spv::OpImageQuerySize: - case spv::OpImageQueryLod: - case spv::OpImageQueryLevels: - case spv::OpImageQuerySamples: - case spv::OpImageSparseSampleImplicitLod: - case spv::OpImageSparseSampleExplicitLod: - case spv::OpImageSparseSampleDrefImplicitLod: - case spv::OpImageSparseSampleDrefExplicitLod: - case spv::OpImageSparseSampleProjImplicitLod: - case spv::OpImageSparseSampleProjExplicitLod: - case spv::OpImageSparseSampleProjDrefImplicitLod: - case spv::OpImageSparseSampleProjDrefExplicitLod: - case spv::OpImageSparseFetch: - case spv::OpImageSparseGather: - case spv::OpImageSparseDrefGather: - case spv::OpImageTexelPointer: - worklist.insert(insn.word(3)); /* image or sampled image */ - break; - case spv::OpImageWrite: - worklist.insert(insn.word(1)); /* image -- different operand order to above */ - break; - case spv::OpFunctionCall: - for (auto i = 3; i < insn.len(); i++) { - worklist.insert(insn.word(i)); /* fn itself, and all args */ - } - break; - - case spv::OpExtInst: - for (auto i = 5; i < insn.len(); i++) { - worklist.insert(insn.word(i)); /* operands to ext inst */ - } - break; - } - } - break; - } - } -} - -struct shader_stage_attributes { - char const *const name; - bool arrayed_input; -}; - -static shader_stage_attributes shader_stage_attribs[] = { - {"vertex shader", false}, - {"tessellation control shader", true}, - {"tessellation evaluation shader", false}, - {"geometry shader", true}, - {"fragment shader", false}, -}; - -static bool validate_push_constant_block_against_pipeline(layer_data *my_data, VkDevice dev, - std::vector<VkPushConstantRange> const *pushConstantRanges, - shader_module const *src, spirv_inst_iter type, - VkShaderStageFlagBits stage) { - bool pass = true; - - /* strip off ptrs etc */ - type = get_struct_type(src, type, false); - assert(type != src->end()); - - /* validate directly off the offsets. this isn't quite correct for arrays - * and matrices, but is a good first step. TODO: arrays, matrices, weird - * sizes */ - for (auto insn : *src) { - if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) { - - if (insn.word(3) == spv::DecorationOffset) { - unsigned offset = insn.word(4); - auto size = 4; /* bytes; TODO: calculate this based on the type */ - - bool found_range = false; - for (auto const &range : *pushConstantRanges) { - if (range.offset <= offset && range.offset + range.size >= offset + size) { - found_range = true; - - if ((range.stageFlags & stage) == 0) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - /* dev */ 0, __LINE__, SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC", - "Push constant range covering variable starting at " - "offset %u not accessible from stage %s", - offset, string_VkShaderStageFlagBits(stage))) { - pass = false; - } - } - - break; - } - } - - if (!found_range) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - /* dev */ 0, __LINE__, SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC", - "Push constant range covering variable starting at " - "offset %u not declared in layout", - offset)) { - pass = false; - } - } - } - } - } - - return pass; -} - -static bool validate_push_constant_usage(layer_data *my_data, VkDevice dev, - std::vector<VkPushConstantRange> const *pushConstantRanges, shader_module const *src, - std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) { - bool pass = true; - - for (auto id : accessible_ids) { - auto def_insn = src->get_def(id); - if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) { - pass = validate_push_constant_block_against_pipeline(my_data, dev, pushConstantRanges, src, - src->get_def(def_insn.word(1)), stage) && - pass; - } - } - - return pass; -} - -// For given pipelineLayout verify that the setLayout at slot.first -// has the requested binding at slot.second -static bool has_descriptor_binding(layer_data *my_data, vector<VkDescriptorSetLayout> *pipelineLayout, descriptor_slot_t slot, - VkDescriptorType &type, VkShaderStageFlags &stage_flags) { - type = VkDescriptorType(0); - stage_flags = VkShaderStageFlags(0); - - if (!pipelineLayout) - return false; - - if (slot.first >= pipelineLayout->size()) - return false; - - auto const layout_node = my_data->descriptorSetLayoutMap[(*pipelineLayout)[slot.first]]; - - auto bindingIt = layout_node->bindingToIndexMap.find(slot.second); - if ((bindingIt == layout_node->bindingToIndexMap.end()) || (layout_node->createInfo.pBindings == NULL)) - return false; - - assert(bindingIt->second < layout_node->createInfo.bindingCount); - VkDescriptorSetLayoutBinding binding = layout_node->createInfo.pBindings[bindingIt->second]; - type = binding.descriptorType; - stage_flags = binding.stageFlags; - - return true; -} - -// Block of code at start here for managing/tracking Pipeline state that this layer cares about - -static uint64_t g_drawCount[NUM_DRAW_TYPES] = {0, 0, 0, 0}; - -// TODO : Should be tracking lastBound per commandBuffer and when draws occur, report based on that cmd buffer lastBound -// Then need to synchronize the accesses based on cmd buffer so that if I'm reading state on one cmd buffer, updates -// to that same cmd buffer by separate thread are not changing state from underneath us -// Track the last cmd buffer touched by this thread - -// prototype -static GLOBAL_CB_NODE *getCBNode(layer_data *, const VkCommandBuffer); - -static VkBool32 hasDrawCmd(GLOBAL_CB_NODE *pCB) { - for (uint32_t i = 0; i < NUM_DRAW_TYPES; i++) { - if (pCB->drawCount[i]) - return VK_TRUE; - } - return VK_FALSE; -} - -// Check object status for selected flag state -static VkBool32 validate_status(layer_data *my_data, GLOBAL_CB_NODE *pNode, CBStatusFlags enable_mask, CBStatusFlags status_mask, - CBStatusFlags status_flag, VkFlags msg_flags, DRAW_STATE_ERROR error_code, const char *fail_msg) { - // If non-zero enable mask is present, check it against status but if enable_mask - // is 0 then no enable required so we should always just check status - if ((!enable_mask) || (enable_mask & pNode->status)) { - if ((pNode->status & status_mask) != status_flag) { - // TODO : How to pass dispatchable objects as srcObject? Here src obj should be cmd buffer - return log_msg(my_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, error_code, - "DS", "CB object %#" PRIxLEAST64 ": %s", (uint64_t)(pNode->commandBuffer), fail_msg); - } - } - return VK_FALSE; -} - -// Retrieve pipeline node ptr for given pipeline object -static PIPELINE_NODE *getPipeline(layer_data *my_data, const VkPipeline pipeline) { - if (my_data->pipelineMap.find(pipeline) == my_data->pipelineMap.end()) { - return NULL; - } - return my_data->pipelineMap[pipeline]; -} - -// Return VK_TRUE if for a given PSO, the given state enum is dynamic, else return VK_FALSE -static VkBool32 isDynamic(const PIPELINE_NODE *pPipeline, const VkDynamicState state) { - if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) { - for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) { - if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) - return VK_TRUE; - } - } - return VK_FALSE; -} - -// Validate state stored as flags at time of draw call -static VkBool32 validate_draw_state_flags(layer_data *my_data, GLOBAL_CB_NODE *pCB, VkBool32 indexedDraw) { - VkBool32 result; - result = - validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_VIEWPORT_SET, CBSTATUS_VIEWPORT_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, - DRAWSTATE_VIEWPORT_NOT_BOUND, "Dynamic viewport state not set for this command buffer"); - result |= - validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_SCISSOR_SET, CBSTATUS_SCISSOR_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, - DRAWSTATE_SCISSOR_NOT_BOUND, "Dynamic scissor state not set for this command buffer"); - result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_LINE_WIDTH_SET, CBSTATUS_LINE_WIDTH_SET, - VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_LINE_WIDTH_NOT_BOUND, - "Dynamic line width state not set for this command buffer"); - result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_DEPTH_BIAS_SET, CBSTATUS_DEPTH_BIAS_SET, - VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_DEPTH_BIAS_NOT_BOUND, - "Dynamic depth bias state not set for this command buffer"); - result |= validate_status(my_data, pCB, CBSTATUS_COLOR_BLEND_WRITE_ENABLE, CBSTATUS_BLEND_SET, CBSTATUS_BLEND_SET, - VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_BLEND_NOT_BOUND, - "Dynamic blend object state not set for this command buffer"); - result |= validate_status(my_data, pCB, CBSTATUS_DEPTH_WRITE_ENABLE, CBSTATUS_DEPTH_BOUNDS_SET, CBSTATUS_DEPTH_BOUNDS_SET, - VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_DEPTH_BOUNDS_NOT_BOUND, - "Dynamic depth bounds state not set for this command buffer"); - result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_READ_MASK_SET, - CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND, - "Dynamic stencil read mask state not set for this command buffer"); - result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_WRITE_MASK_SET, - CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND, - "Dynamic stencil write mask state not set for this command buffer"); - result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_REFERENCE_SET, - CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND, - "Dynamic stencil reference state not set for this command buffer"); - if (indexedDraw) - result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_INDEX_BUFFER_BOUND, CBSTATUS_INDEX_BUFFER_BOUND, - VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_INDEX_BUFFER_NOT_BOUND, - "Index buffer object not bound to this command buffer when Indexed Draw attempted"); - return result; -} - -// Verify attachment reference compatibility according to spec -// If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this -// If both AttachmentReference arrays have requested index, check their corresponding AttachementDescriptions -// to make sure that format and samples counts match. -// If not, they are not compatible. -static bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary, - const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments, - const VkAttachmentReference *pSecondary, const uint32_t secondaryCount, - const VkAttachmentDescription *pSecondaryAttachments) { - if (index >= primaryCount) { // Check secondary as if primary is VK_ATTACHMENT_UNUSED - if (VK_ATTACHMENT_UNUSED != pSecondary[index].attachment) - return false; - } else if (index >= secondaryCount) { // Check primary as if secondary is VK_ATTACHMENT_UNUSED - if (VK_ATTACHMENT_UNUSED != pPrimary[index].attachment) - return false; - } else { // format and sample count must match - if ((pPrimaryAttachments[pPrimary[index].attachment].format == - pSecondaryAttachments[pSecondary[index].attachment].format) && - (pPrimaryAttachments[pPrimary[index].attachment].samples == - pSecondaryAttachments[pSecondary[index].attachment].samples)) - return true; - } - // Format and sample counts didn't match - return false; -} - -// For give primary and secondary RenderPass objects, verify that they're compatible -static bool verify_renderpass_compatibility(layer_data *my_data, const VkRenderPass primaryRP, const VkRenderPass secondaryRP, - string &errorMsg) { - stringstream errorStr; - if (my_data->renderPassMap.find(primaryRP) == my_data->renderPassMap.end()) { - errorStr << "invalid VkRenderPass (" << primaryRP << ")"; - errorMsg = errorStr.str(); - return false; - } else if (my_data->renderPassMap.find(secondaryRP) == my_data->renderPassMap.end()) { - errorStr << "invalid VkRenderPass (" << secondaryRP << ")"; - errorMsg = errorStr.str(); - return false; - } - // Trivial pass case is exact same RP - if (primaryRP == secondaryRP) { - return true; - } - const VkRenderPassCreateInfo *primaryRPCI = my_data->renderPassMap[primaryRP]->pCreateInfo; - const VkRenderPassCreateInfo *secondaryRPCI = my_data->renderPassMap[secondaryRP]->pCreateInfo; - if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) { - errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount - << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses."; - errorMsg = errorStr.str(); - return false; - } - uint32_t spIndex = 0; - for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) { - // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible - uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount; - uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount; - uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount); - for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) { - if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount, - primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments, - secondaryColorCount, secondaryRPCI->pAttachments)) { - errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible."; - errorMsg = errorStr.str(); - return false; - } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments, - primaryColorCount, primaryRPCI->pAttachments, - secondaryRPCI->pSubpasses[spIndex].pResolveAttachments, - secondaryColorCount, secondaryRPCI->pAttachments)) { - errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible."; - errorMsg = errorStr.str(); - return false; - } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, - primaryColorCount, primaryRPCI->pAttachments, - secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, - secondaryColorCount, secondaryRPCI->pAttachments)) { - errorStr << "depth/stencil attachments at index " << cIdx << " of subpass index " << spIndex - << " are not compatible."; - errorMsg = errorStr.str(); - return false; - } - } - uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount; - uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount; - uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount); - for (uint32_t i = 0; i < inputMax; ++i) { - if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryColorCount, - primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments, - secondaryColorCount, secondaryRPCI->pAttachments)) { - errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible."; - errorMsg = errorStr.str(); - return false; - } - } - } - return true; -} - -// For give SET_NODE, verify that its Set is compatible w/ the setLayout corresponding to pipelineLayout[layoutIndex] -static bool verify_set_layout_compatibility(layer_data *my_data, const SET_NODE *pSet, const VkPipelineLayout layout, - const uint32_t layoutIndex, string &errorMsg) { - stringstream errorStr; - if (my_data->pipelineLayoutMap.find(layout) == my_data->pipelineLayoutMap.end()) { - errorStr << "invalid VkPipelineLayout (" << layout << ")"; - errorMsg = errorStr.str(); - return false; - } - PIPELINE_LAYOUT_NODE pl = my_data->pipelineLayoutMap[layout]; - if (layoutIndex >= pl.descriptorSetLayouts.size()) { - errorStr << "VkPipelineLayout (" << layout << ") only contains " << pl.descriptorSetLayouts.size() - << " setLayouts corresponding to sets 0-" << pl.descriptorSetLayouts.size() - 1 - << ", but you're attempting to bind set to index " << layoutIndex; - errorMsg = errorStr.str(); - return false; - } - // Get the specific setLayout from PipelineLayout that overlaps this set - LAYOUT_NODE *pLayoutNode = my_data->descriptorSetLayoutMap[pl.descriptorSetLayouts[layoutIndex]]; - if (pLayoutNode->layout == pSet->pLayout->layout) { // trivial pass case - return true; - } - size_t descriptorCount = pLayoutNode->descriptorTypes.size(); - if (descriptorCount != pSet->pLayout->descriptorTypes.size()) { - errorStr << "setLayout " << layoutIndex << " from pipelineLayout " << layout << " has " << descriptorCount - << " descriptors, but corresponding set being bound has " << pSet->pLayout->descriptorTypes.size() - << " descriptors."; - errorMsg = errorStr.str(); - return false; // trivial fail case - } - // Now need to check set against corresponding pipelineLayout to verify compatibility - for (size_t i = 0; i < descriptorCount; ++i) { - // Need to verify that layouts are identically defined - // TODO : Is below sufficient? Making sure that types & stageFlags match per descriptor - // do we also need to check immutable samplers? - if (pLayoutNode->descriptorTypes[i] != pSet->pLayout->descriptorTypes[i]) { - errorStr << "descriptor " << i << " for descriptorSet being bound is type '" - << string_VkDescriptorType(pSet->pLayout->descriptorTypes[i]) - << "' but corresponding descriptor from pipelineLayout is type '" - << string_VkDescriptorType(pLayoutNode->descriptorTypes[i]) << "'"; - errorMsg = errorStr.str(); - return false; - } - if (pLayoutNode->stageFlags[i] != pSet->pLayout->stageFlags[i]) { - errorStr << "stageFlags " << i << " for descriptorSet being bound is " << pSet->pLayout->stageFlags[i] - << "' but corresponding descriptor from pipelineLayout has stageFlags " << pLayoutNode->stageFlags[i]; - errorMsg = errorStr.str(); - return false; - } - } - return true; -} - -// Validate that data for each specialization entry is fully contained within the buffer. -static VkBool32 validate_specialization_offsets(layer_data *my_data, VkPipelineShaderStageCreateInfo const *info) { - VkBool32 pass = VK_TRUE; - - VkSpecializationInfo const *spec = info->pSpecializationInfo; - - if (spec) { - for (auto i = 0u; i < spec->mapEntryCount; i++) { - if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - /*dev*/ 0, __LINE__, SHADER_CHECKER_BAD_SPECIALIZATION, "SC", - "Specialization entry %u (for constant id %u) references memory outside provided " - "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER - " bytes provided)", - i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset, - spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize)) { - - pass = VK_FALSE; - } - } - } - } - - return pass; -} - -static bool descriptor_type_match(layer_data *my_data, shader_module const *module, uint32_t type_id, - VkDescriptorType descriptor_type) { - auto type = module->get_def(type_id); - - /* Strip off any array or ptrs */ - /* TODO: if we see an array type here, we should make use of it in order to - * validate the number of descriptors actually required to be set in the - * API. - */ - while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) { - type = module->get_def(type.word(type.opcode() == spv::OpTypeArray ? 2 : 3)); - } - - switch (type.opcode()) { - case spv::OpTypeStruct: { - for (auto insn : *module) { - if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) { - if (insn.word(2) == spv::DecorationBlock) { - return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || - descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - } else if (insn.word(2) == spv::DecorationBufferBlock) { - return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || - descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; - } - } - } - - /* Invalid */ - return false; - } - - case spv::OpTypeSampler: - return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER; - - case spv::OpTypeSampledImage: - return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - - case spv::OpTypeImage: { - /* Many descriptor types backing image types-- depends on dimension - * and whether the image will be used with a sampler. SPIRV for - * Vulkan requires that sampled be 1 or 2 -- leaving the decision to - * runtime is unacceptable. - */ - auto dim = type.word(3); - auto sampled = type.word(7); - - if (dim == spv::DimSubpassData) { - return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; - } else if (dim == spv::DimBuffer) { - if (sampled == 1) { - return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; - } else { - return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - } - } else if (sampled == 1) { - return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - } else { - return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - } - } - - /* We shouldn't really see any other junk types -- but if we do, they're - * a mismatch. - */ - default: - return false; /* Mismatch */ - } -} - -// Validate that the shaders used by the given pipeline -// As a side effect this function also records the sets that are actually used by the pipeline -static VkBool32 validate_pipeline_shaders(layer_data *my_data, VkDevice dev, PIPELINE_NODE *pPipeline) { - VkGraphicsPipelineCreateInfo const *pCreateInfo = &pPipeline->graphicsPipelineCI; - /* We seem to allow pipeline stages to be specified out of order, so collect and identify them - * before trying to do anything more: */ - int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT); - int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT); - - shader_module *shaders[5]; - memset(shaders, 0, sizeof(shaders)); - spirv_inst_iter entrypoints[5]; - memset(entrypoints, 0, sizeof(entrypoints)); - RENDER_PASS_NODE const *rp = 0; - VkPipelineVertexInputStateCreateInfo const *vi = 0; - VkBool32 pass = VK_TRUE; - - for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { - VkPipelineShaderStageCreateInfo const *pStage = &pCreateInfo->pStages[i]; - if (pStage->sType == VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO) { - - if ((pStage->stage & (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | - VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) == 0) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - /*dev*/ 0, __LINE__, SHADER_CHECKER_UNKNOWN_STAGE, "SC", "Unknown shader stage %d", pStage->stage)) { - pass = VK_FALSE; - } - } else { - pass = validate_specialization_offsets(my_data, pStage) && pass; - - auto stage_id = get_shader_stage_id(pStage->stage); - shader_module *module = my_data->shaderModuleMap[pStage->module]; - shaders[stage_id] = module; - - /* find the entrypoint */ - entrypoints[stage_id] = find_entrypoint(module, pStage->pName, pStage->stage); - if (entrypoints[stage_id] == module->end()) { - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - /*dev*/ 0, __LINE__, SHADER_CHECKER_MISSING_ENTRYPOINT, "SC", - "No entrypoint found named `%s` for stage %s", pStage->pName, - string_VkShaderStageFlagBits(pStage->stage))) { - pass = VK_FALSE; - } - } - - /* mark accessible ids */ - std::unordered_set<uint32_t> accessible_ids; - mark_accessible_ids(module, entrypoints[stage_id], accessible_ids); - - /* validate descriptor set layout against what the entrypoint actually uses */ - std::map<descriptor_slot_t, interface_var> descriptor_uses; - collect_interface_by_descriptor_slot(my_data, dev, module, accessible_ids, descriptor_uses); - - auto layouts = pCreateInfo->layout != VK_NULL_HANDLE - ? &(my_data->pipelineLayoutMap[pCreateInfo->layout].descriptorSetLayouts) - : nullptr; - - for (auto it = descriptor_uses.begin(); it != descriptor_uses.end(); it++) { - // As a side-effect of this function, capture which sets are used by the pipeline - pPipeline->active_sets.insert(it->first.first); - - /* find the matching binding */ - VkDescriptorType descriptor_type; - VkShaderStageFlags descriptor_stage_flags; - auto found = has_descriptor_binding(my_data, layouts, it->first, descriptor_type, descriptor_stage_flags); - - if (!found) { - char type_name[1024]; - describe_type(type_name, module, it->second.type_id); - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - /*dev*/ 0, __LINE__, SHADER_CHECKER_MISSING_DESCRIPTOR, "SC", - "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout", - it->first.first, it->first.second, type_name)) { - pass = VK_FALSE; - } - } else if (~descriptor_stage_flags & pStage->stage) { - char type_name[1024]; - describe_type(type_name, module, it->second.type_id); - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC", - "Shader uses descriptor slot %u.%u (used " - "as type `%s`) but descriptor not " - "accessible from stage %s", - it->first.first, it->first.second, type_name, string_VkShaderStageFlagBits(pStage->stage))) { - pass = VK_FALSE; - } - } else if (!descriptor_type_match(my_data, module, it->second.type_id, descriptor_type)) { - char type_name[1024]; - describe_type(type_name, module, it->second.type_id); - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC", - "Type mismatch on descriptor slot " - "%u.%u (used as type `%s`) but " - "descriptor of type %s", - it->first.first, it->first.second, type_name, string_VkDescriptorType(descriptor_type))) { - pass = VK_FALSE; - } - } - } - - /* validate push constant usage */ - pass = - validate_push_constant_usage(my_data, dev, &my_data->pipelineLayoutMap[pCreateInfo->layout].pushConstantRanges, - module, accessible_ids, pStage->stage) && - pass; - } - } - } - - if (pCreateInfo->renderPass != VK_NULL_HANDLE) - rp = my_data->renderPassMap[pCreateInfo->renderPass]; - - vi = pCreateInfo->pVertexInputState; - - if (vi) { - pass = validate_vi_consistency(my_data, dev, vi) && pass; - } - - if (shaders[vertex_stage]) { - pass = validate_vi_against_vs_inputs(my_data, dev, vi, shaders[vertex_stage], entrypoints[vertex_stage]) && pass; - } - - /* TODO: enforce rules about present combinations of shaders */ - int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT); - int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); - - while (!shaders[producer] && producer != fragment_stage) { - producer++; - consumer++; - } - - for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) { - assert(shaders[producer]); - if (shaders[consumer]) { - pass = validate_interface_between_stages(my_data, dev, shaders[producer], entrypoints[producer], - shader_stage_attribs[producer].name, shaders[consumer], entrypoints[consumer], - shader_stage_attribs[consumer].name, - shader_stage_attribs[consumer].arrayed_input) && - pass; - - producer = consumer; - } - } - - if (shaders[fragment_stage] && rp) { - pass = validate_fs_outputs_against_render_pass(my_data, dev, shaders[fragment_stage], entrypoints[fragment_stage], rp, - pCreateInfo->subpass) && - pass; - } - - return pass; -} - -// Return Set node ptr for specified set or else NULL -static SET_NODE *getSetNode(layer_data *my_data, const VkDescriptorSet set) { - if (my_data->setMap.find(set) == my_data->setMap.end()) { - return NULL; - } - return my_data->setMap[set]; -} -// For the given command buffer, verify that for each set set in activeSetNodes -// that any dynamic descriptor in that set has a valid dynamic offset bound. -// To be valid, the dynamic offset combined with the offet and range from its -// descriptor update must not overflow the size of its buffer being updated -static VkBool32 validate_dynamic_offsets(layer_data *my_data, const GLOBAL_CB_NODE *pCB, const vector<SET_NODE *> activeSetNodes) { - VkBool32 result = VK_FALSE; - - VkWriteDescriptorSet *pWDS = NULL; - uint32_t dynOffsetIndex = 0; - VkDeviceSize bufferSize = 0; - for (auto set_node : activeSetNodes) { - for (uint32_t i = 0; i < set_node->descriptorCount; ++i) { - // TODO: Add validation for descriptors dynamically skipped in shader - if (set_node->ppDescriptors[i] != NULL) { - switch (set_node->ppDescriptors[i]->sType) { - case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: - pWDS = (VkWriteDescriptorSet *)set_node->ppDescriptors[i]; - if ((pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) || - (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) { - for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) { - bufferSize = my_data->bufferMap[pWDS->pBufferInfo[j].buffer].create_info->size; - if (pWDS->pBufferInfo[j].range == VK_WHOLE_SIZE) { - if ((pCB->dynamicOffsets[dynOffsetIndex] + pWDS->pBufferInfo[j].offset) > bufferSize) { - result |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)set_node->set, __LINE__, - DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS", - "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has range of " - "VK_WHOLE_SIZE but dynamic offset %u " - "combined with offet %#" PRIxLEAST64 " oversteps its buffer (%#" PRIxLEAST64 - ") which has a size of %#" PRIxLEAST64 ".", - (uint64_t)set_node->set, i, pCB->dynamicOffsets[dynOffsetIndex], - pWDS->pBufferInfo[j].offset, (uint64_t)pWDS->pBufferInfo[j].buffer, bufferSize); - } - } else if ((pCB->dynamicOffsets[dynOffsetIndex] + pWDS->pBufferInfo[j].offset + - pWDS->pBufferInfo[j].range) > bufferSize) { - result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)set_node->set, __LINE__, - DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS", - "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has dynamic offset %u. " - "Combined with offet %#" PRIxLEAST64 " and range %#" PRIxLEAST64 - " from its update, this oversteps its buffer " - "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".", - (uint64_t)set_node->set, i, pCB->dynamicOffsets[dynOffsetIndex], - pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range, - (uint64_t)pWDS->pBufferInfo[j].buffer, bufferSize); - } else if ((pCB->dynamicOffsets[dynOffsetIndex] + pWDS->pBufferInfo[j].offset + - pWDS->pBufferInfo[j].range) > bufferSize) { - result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)set_node->set, __LINE__, - DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS", - "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has dynamic offset %u. " - "Combined with offet %#" PRIxLEAST64 " and range %#" PRIxLEAST64 - " from its update, this oversteps its buffer " - "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".", - (uint64_t)set_node->set, i, pCB->dynamicOffsets[dynOffsetIndex], - pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range, - (uint64_t)pWDS->pBufferInfo[j].buffer, bufferSize); - } - dynOffsetIndex++; - i += j; // Advance i to end of this set of descriptors (++i at end of for loop will move 1 index past - // last of these descriptors) - } - } - break; - default: // Currently only shadowing Write update nodes so shouldn't get here - assert(0); - continue; - } - } - } - } - return result; -} - -// Validate overall state at the time of a draw call -static VkBool32 validate_draw_state(layer_data *my_data, GLOBAL_CB_NODE *pCB, VkBool32 indexedDraw) { - // First check flag states - VkBool32 result = validate_draw_state_flags(my_data, pCB, indexedDraw); - PIPELINE_NODE *pPipe = getPipeline(my_data, pCB->lastBoundPipeline); - // Now complete other state checks - // TODO : Currently only performing next check if *something* was bound (non-zero last bound) - // There is probably a better way to gate when this check happens, and to know if something *should* have been bound - // We should have that check separately and then gate this check based on that check - if (pPipe) { - if (pCB->lastBoundPipelineLayout) { - string errorString; - // Need a vector (vs. std::set) of active Sets for dynamicOffset validation in case same set bound w/ different offsets - vector<SET_NODE *> activeSetNodes; - for (auto setIndex : pPipe->active_sets) { - // If valid set is not bound throw an error - if ((pCB->boundDescriptorSets.size() <= setIndex) || (!pCB->boundDescriptorSets[setIndex])) { - result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS", - "VkPipeline %#" PRIxLEAST64 " uses set #%u but that set is not bound.", - (uint64_t)pPipe->pipeline, setIndex); - } else if (!verify_set_layout_compatibility(my_data, my_data->setMap[pCB->boundDescriptorSets[setIndex]], - pPipe->graphicsPipelineCI.layout, setIndex, errorString)) { - // Set is bound but not compatible w/ overlapping pipelineLayout from PSO - VkDescriptorSet setHandle = my_data->setMap[pCB->boundDescriptorSets[setIndex]]->set; - result |= log_msg( - my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - (uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS", - "VkDescriptorSet (%#" PRIxLEAST64 - ") bound as set #%u is not compatible with overlapping VkPipelineLayout %#" PRIxLEAST64 " due to: %s", - (uint64_t)setHandle, setIndex, (uint64_t)pPipe->graphicsPipelineCI.layout, errorString.c_str()); - } else { // Valid set is bound and layout compatible, validate that it's updated and verify any dynamic offsets - // Pull the set node - SET_NODE *pSet = my_data->setMap[pCB->boundDescriptorSets[setIndex]]; - // Save vector of all active sets to verify dynamicOffsets below - activeSetNodes.push_back(pSet); - // Make sure set has been updated - if (!pSet->pUpdateStructs) { - result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pSet->set, __LINE__, - DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS", - "DS %#" PRIxLEAST64 " bound but it was never updated. It is now being used to draw so " - "this will result in undefined behavior.", - (uint64_t)pSet->set); - } - } - } - // For each dynamic descriptor, make sure dynamic offset doesn't overstep buffer - if (!pCB->dynamicOffsets.empty()) - result |= validate_dynamic_offsets(my_data, pCB, activeSetNodes); - } - // Verify Vtx binding - if (pPipe->vtxBindingCount > 0) { - VkPipelineVertexInputStateCreateInfo *vtxInCI = &pPipe->vertexInputCI; - for (uint32_t i = 0; i < vtxInCI->vertexBindingDescriptionCount; i++) { - if ((pCB->currentDrawData.buffers.size() < (i + 1)) || (pCB->currentDrawData.buffers[i] == VK_NULL_HANDLE)) { - result |= log_msg( - my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS", - "The Pipeline State Object (%#" PRIxLEAST64 - ") expects that this Command Buffer's vertex binding Index %d should be set via vkCmdBindVertexBuffers.", - (uint64_t)pCB->lastBoundPipeline, i); - } - } - } else { - if (!pCB->currentDrawData.buffers.empty()) { - result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, - 0, __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS", - "Vertex buffers are bound to command buffer (%#" PRIxLEAST64 - ") but no vertex buffers are attached to this Pipeline State Object (%#" PRIxLEAST64 ").", - (uint64_t)pCB->commandBuffer, (uint64_t)pCB->lastBoundPipeline); - } - } - // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count. - // Skip check if rasterization is disabled or there is no viewport. - if ((!pPipe->graphicsPipelineCI.pRasterizationState || - !pPipe->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) && - pPipe->graphicsPipelineCI.pViewportState) { - VkBool32 dynViewport = isDynamic(pPipe, VK_DYNAMIC_STATE_VIEWPORT); - VkBool32 dynScissor = isDynamic(pPipe, VK_DYNAMIC_STATE_SCISSOR); - if (dynViewport) { - if (pCB->viewports.size() != pPipe->graphicsPipelineCI.pViewportState->viewportCount) { - result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", - "Dynamic viewportCount from vkCmdSetViewport() is " PRINTF_SIZE_T_SPECIFIER - ", but PSO viewportCount is %u. These counts must match.", - pCB->viewports.size(), pPipe->graphicsPipelineCI.pViewportState->viewportCount); - } - } - if (dynScissor) { - if (pCB->scissors.size() != pPipe->graphicsPipelineCI.pViewportState->scissorCount) { - result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", - "Dynamic scissorCount from vkCmdSetScissor() is " PRINTF_SIZE_T_SPECIFIER - ", but PSO scissorCount is %u. These counts must match.", - pCB->scissors.size(), pPipe->graphicsPipelineCI.pViewportState->scissorCount); - } - } - } - } - return result; -} - -// Verify that create state for a pipeline is valid -static VkBool32 verifyPipelineCreateState(layer_data *my_data, const VkDevice device, std::vector<PIPELINE_NODE *> pPipelines, - int pipelineIndex) { - VkBool32 skipCall = VK_FALSE; - - PIPELINE_NODE *pPipeline = pPipelines[pipelineIndex]; - - // If create derivative bit is set, check that we've specified a base - // pipeline correctly, and that the base pipeline was created to allow - // derivatives. - if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) { - PIPELINE_NODE *pBasePipeline = nullptr; - if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^ - (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", - "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified"); - } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) { - if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", - "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline."); - } else { - pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex]; - } - } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) { - pBasePipeline = getPipeline(my_data, pPipeline->graphicsPipelineCI.basePipelineHandle); - } - - if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", - "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives."); - } - } - - if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) { - if (!my_data->physDevProperties.features.independentBlend) { - VkPipelineColorBlendAttachmentState *pAttachments = pPipeline->pAttachments; - for (uint32_t i = 1; i < pPipeline->attachmentCount; i++) { - if ((pAttachments[0].blendEnable != pAttachments[i].blendEnable) || - (pAttachments[0].srcColorBlendFactor != pAttachments[i].srcColorBlendFactor) || - (pAttachments[0].dstColorBlendFactor != pAttachments[i].dstColorBlendFactor) || - (pAttachments[0].colorBlendOp != pAttachments[i].colorBlendOp) || - (pAttachments[0].srcAlphaBlendFactor != pAttachments[i].srcAlphaBlendFactor) || - (pAttachments[0].dstAlphaBlendFactor != pAttachments[i].dstAlphaBlendFactor) || - (pAttachments[0].alphaBlendOp != pAttachments[i].alphaBlendOp) || - (pAttachments[0].colorWriteMask != pAttachments[i].colorWriteMask)) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INDEPENDENT_BLEND, "DS", "Invalid Pipeline CreateInfo: If independent blend feature not " - "enabled, all elements of pAttachments must be identical"); - } - } - } - if (!my_data->physDevProperties.features.logicOp && - (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_DISABLED_LOGIC_OP, "DS", - "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE"); - } - if ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable == VK_TRUE) && - ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOp < VK_LOGIC_OP_CLEAR) || - (pPipeline->graphicsPipelineCI.pColorBlendState->logicOp > VK_LOGIC_OP_SET))) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_LOGIC_OP, "DS", - "Invalid Pipeline CreateInfo: If logicOpEnable is VK_TRUE, logicOp must be a valid VkLogicOp value"); - } - } - - // Ensure the subpass index is valid. If not, then validate_pipeline_shaders - // produces nonsense errors that confuse users. Other layers should already - // emit errors for renderpass being invalid. - auto rp_data = my_data->renderPassMap.find(pPipeline->graphicsPipelineCI.renderPass); - if (rp_data != my_data->renderPassMap.end() && - pPipeline->graphicsPipelineCI.subpass >= rp_data->second->pCreateInfo->subpassCount) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Subpass index %u " - "is out of range for this renderpass (0..%u)", - pPipeline->graphicsPipelineCI.subpass, rp_data->second->pCreateInfo->subpassCount - 1); - } - - if (!validate_pipeline_shaders(my_data, device, pPipeline)) { - skipCall = VK_TRUE; - } - // VS is required - if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Vtx Shader required"); - } - // Either both or neither TC/TE shaders should be defined - if (((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) == 0) != - ((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) == 0)) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", - "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair"); - } - // Compute shaders should be specified independent of Gfx shaders - if ((pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) && - (pPipeline->active_shaders & - (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | - VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT))) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", - "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline"); - } - // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines. - // Mismatching primitive topology and tessellation fails graphics pipeline creation. - if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) && - (pPipeline->iaStateCI.topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: " - "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA " - "topology for tessellation pipelines"); - } - if (pPipeline->iaStateCI.topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) { - if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: " - "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive " - "topology is only valid for tessellation pipelines"); - } - if (!pPipeline->tessStateCI.patchControlPoints || (pPipeline->tessStateCI.patchControlPoints > 32)) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: " - "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive " - "topology used with patchControlPoints value %u." - " patchControlPoints should be >0 and <=32.", - pPipeline->tessStateCI.patchControlPoints); - } - } - // Viewport state must be included if rasterization is enabled. - // If the viewport state is included, the viewport and scissor counts should always match. - // NOTE : Even if these are flagged as dynamic, counts need to be set correctly for shader compiler - if (!pPipeline->graphicsPipelineCI.pRasterizationState || - !pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) { - if (!pPipeline->graphicsPipelineCI.pViewportState) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "Gfx Pipeline pViewportState is null. Even if viewport " - "and scissors are dynamic PSO must include " - "viewportCount and scissorCount in pViewportState."); - } else if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount != - pPipeline->graphicsPipelineCI.pViewportState->viewportCount) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", - "Gfx Pipeline viewport count (%u) must match scissor count (%u).", - pPipeline->vpStateCI.viewportCount, pPipeline->vpStateCI.scissorCount); - } else { - // If viewport or scissor are not dynamic, then verify that data is appropriate for count - VkBool32 dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT); - VkBool32 dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR); - if (!dynViewport) { - if (pPipeline->graphicsPipelineCI.pViewportState->viewportCount && - !pPipeline->graphicsPipelineCI.pViewportState->pViewports) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", - "Gfx Pipeline viewportCount is %u, but pViewports is NULL. For non-zero viewportCount, you " - "must either include pViewports data, or include viewport in pDynamicState and set it with " - "vkCmdSetViewport().", - pPipeline->graphicsPipelineCI.pViewportState->viewportCount); - } - } - if (!dynScissor) { - if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount && - !pPipeline->graphicsPipelineCI.pViewportState->pScissors) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", - "Gfx Pipeline scissorCount is %u, but pScissors is NULL. For non-zero scissorCount, you " - "must either include pScissors data, or include scissor in pDynamicState and set it with " - "vkCmdSetScissor().", - pPipeline->graphicsPipelineCI.pViewportState->scissorCount); - } - } - } - } - return skipCall; -} - -// Init the pipeline mapping info based on pipeline create info LL tree -// Threading note : Calls to this function should wrapped in mutex -// TODO : this should really just be in the constructor for PIPELINE_NODE -static PIPELINE_NODE *initGraphicsPipeline(layer_data *dev_data, const VkGraphicsPipelineCreateInfo *pCreateInfo) { - PIPELINE_NODE *pPipeline = new PIPELINE_NODE; - - // First init create info - memcpy(&pPipeline->graphicsPipelineCI, pCreateInfo, sizeof(VkGraphicsPipelineCreateInfo)); - - size_t bufferSize = 0; - const VkPipelineVertexInputStateCreateInfo *pVICI = NULL; - const VkPipelineColorBlendStateCreateInfo *pCBCI = NULL; - - for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { - const VkPipelineShaderStageCreateInfo *pPSSCI = &pCreateInfo->pStages[i]; - - switch (pPSSCI->stage) { - case VK_SHADER_STAGE_VERTEX_BIT: - memcpy(&pPipeline->vsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); - pPipeline->active_shaders |= VK_SHADER_STAGE_VERTEX_BIT; - break; - case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: - memcpy(&pPipeline->tcsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); - pPipeline->active_shaders |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - break; - case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: - memcpy(&pPipeline->tesCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); - pPipeline->active_shaders |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - break; - case VK_SHADER_STAGE_GEOMETRY_BIT: - memcpy(&pPipeline->gsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); - pPipeline->active_shaders |= VK_SHADER_STAGE_GEOMETRY_BIT; - break; - case VK_SHADER_STAGE_FRAGMENT_BIT: - memcpy(&pPipeline->fsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo)); - pPipeline->active_shaders |= VK_SHADER_STAGE_FRAGMENT_BIT; - break; - case VK_SHADER_STAGE_COMPUTE_BIT: - // TODO : Flag error, CS is specified through VkComputePipelineCreateInfo - pPipeline->active_shaders |= VK_SHADER_STAGE_COMPUTE_BIT; - break; - default: - // TODO : Flag error - break; - } - } - // Copy over GraphicsPipelineCreateInfo structure embedded pointers - if (pCreateInfo->stageCount != 0) { - pPipeline->graphicsPipelineCI.pStages = new VkPipelineShaderStageCreateInfo[pCreateInfo->stageCount]; - bufferSize = pCreateInfo->stageCount * sizeof(VkPipelineShaderStageCreateInfo); - memcpy((void *)pPipeline->graphicsPipelineCI.pStages, pCreateInfo->pStages, bufferSize); - } - if (pCreateInfo->pVertexInputState != NULL) { - memcpy((void *)&pPipeline->vertexInputCI, pCreateInfo->pVertexInputState, sizeof(VkPipelineVertexInputStateCreateInfo)); - // Copy embedded ptrs - pVICI = pCreateInfo->pVertexInputState; - pPipeline->vtxBindingCount = pVICI->vertexBindingDescriptionCount; - if (pPipeline->vtxBindingCount) { - pPipeline->pVertexBindingDescriptions = new VkVertexInputBindingDescription[pPipeline->vtxBindingCount]; - bufferSize = pPipeline->vtxBindingCount * sizeof(VkVertexInputBindingDescription); - memcpy((void *)pPipeline->pVertexBindingDescriptions, pVICI->pVertexBindingDescriptions, bufferSize); - } - pPipeline->vtxAttributeCount = pVICI->vertexAttributeDescriptionCount; - if (pPipeline->vtxAttributeCount) { - pPipeline->pVertexAttributeDescriptions = new VkVertexInputAttributeDescription[pPipeline->vtxAttributeCount]; - bufferSize = pPipeline->vtxAttributeCount * sizeof(VkVertexInputAttributeDescription); - memcpy((void *)pPipeline->pVertexAttributeDescriptions, pVICI->pVertexAttributeDescriptions, bufferSize); - } - pPipeline->graphicsPipelineCI.pVertexInputState = &pPipeline->vertexInputCI; - } - if (pCreateInfo->pInputAssemblyState != NULL) { - memcpy((void *)&pPipeline->iaStateCI, pCreateInfo->pInputAssemblyState, sizeof(VkPipelineInputAssemblyStateCreateInfo)); - pPipeline->graphicsPipelineCI.pInputAssemblyState = &pPipeline->iaStateCI; - } - if (pCreateInfo->pTessellationState != NULL) { - memcpy((void *)&pPipeline->tessStateCI, pCreateInfo->pTessellationState, sizeof(VkPipelineTessellationStateCreateInfo)); - pPipeline->graphicsPipelineCI.pTessellationState = &pPipeline->tessStateCI; - } - if (pCreateInfo->pViewportState != NULL) { - memcpy((void *)&pPipeline->vpStateCI, pCreateInfo->pViewportState, sizeof(VkPipelineViewportStateCreateInfo)); - pPipeline->graphicsPipelineCI.pViewportState = &pPipeline->vpStateCI; - } - if (pCreateInfo->pRasterizationState != NULL) { - memcpy((void *)&pPipeline->rsStateCI, pCreateInfo->pRasterizationState, sizeof(VkPipelineRasterizationStateCreateInfo)); - pPipeline->graphicsPipelineCI.pRasterizationState = &pPipeline->rsStateCI; - } - if (pCreateInfo->pMultisampleState != NULL) { - memcpy((void *)&pPipeline->msStateCI, pCreateInfo->pMultisampleState, sizeof(VkPipelineMultisampleStateCreateInfo)); - pPipeline->graphicsPipelineCI.pMultisampleState = &pPipeline->msStateCI; - } - if (pCreateInfo->pDepthStencilState != NULL) { - memcpy((void *)&pPipeline->dsStateCI, pCreateInfo->pDepthStencilState, sizeof(VkPipelineDepthStencilStateCreateInfo)); - pPipeline->graphicsPipelineCI.pDepthStencilState = &pPipeline->dsStateCI; - } - if (pCreateInfo->pColorBlendState != NULL) { - memcpy((void *)&pPipeline->cbStateCI, pCreateInfo->pColorBlendState, sizeof(VkPipelineColorBlendStateCreateInfo)); - // Copy embedded ptrs - pCBCI = pCreateInfo->pColorBlendState; - pPipeline->attachmentCount = pCBCI->attachmentCount; - if (pPipeline->attachmentCount) { - pPipeline->pAttachments = new VkPipelineColorBlendAttachmentState[pPipeline->attachmentCount]; - bufferSize = pPipeline->attachmentCount * sizeof(VkPipelineColorBlendAttachmentState); - memcpy((void *)pPipeline->pAttachments, pCBCI->pAttachments, bufferSize); - } - pPipeline->graphicsPipelineCI.pColorBlendState = &pPipeline->cbStateCI; - } - if (pCreateInfo->pDynamicState != NULL) { - memcpy((void *)&pPipeline->dynStateCI, pCreateInfo->pDynamicState, sizeof(VkPipelineDynamicStateCreateInfo)); - if (pPipeline->dynStateCI.dynamicStateCount) { - pPipeline->dynStateCI.pDynamicStates = new VkDynamicState[pPipeline->dynStateCI.dynamicStateCount]; - bufferSize = pPipeline->dynStateCI.dynamicStateCount * sizeof(VkDynamicState); - memcpy((void *)pPipeline->dynStateCI.pDynamicStates, pCreateInfo->pDynamicState->pDynamicStates, bufferSize); - } - pPipeline->graphicsPipelineCI.pDynamicState = &pPipeline->dynStateCI; - } - pPipeline->active_sets.clear(); - return pPipeline; -} - -// Free the Pipeline nodes -static void deletePipelines(layer_data *my_data) { - if (my_data->pipelineMap.size() <= 0) - return; - for (auto ii = my_data->pipelineMap.begin(); ii != my_data->pipelineMap.end(); ++ii) { - if ((*ii).second->graphicsPipelineCI.stageCount != 0) { - delete[](*ii).second->graphicsPipelineCI.pStages; - } - delete[](*ii).second->pVertexBindingDescriptions; - delete[](*ii).second->pVertexAttributeDescriptions; - delete[](*ii).second->pAttachments; - if ((*ii).second->dynStateCI.dynamicStateCount != 0) { - delete[](*ii).second->dynStateCI.pDynamicStates; - } - delete (*ii).second; - } - my_data->pipelineMap.clear(); -} - -// For given pipeline, return number of MSAA samples, or one if MSAA disabled -static VkSampleCountFlagBits getNumSamples(layer_data *my_data, const VkPipeline pipeline) { - PIPELINE_NODE *pPipe = my_data->pipelineMap[pipeline]; - if (VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pPipe->msStateCI.sType) { - return pPipe->msStateCI.rasterizationSamples; - } - return VK_SAMPLE_COUNT_1_BIT; -} - -// Validate state related to the PSO -static VkBool32 validatePipelineState(layer_data *my_data, const GLOBAL_CB_NODE *pCB, const VkPipelineBindPoint pipelineBindPoint, - const VkPipeline pipeline) { - if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) { - // Verify that any MSAA request in PSO matches sample# in bound FB - // Skip the check if rasterization is disabled. - PIPELINE_NODE *pPipeline = my_data->pipelineMap[pipeline]; - if (!pPipeline->graphicsPipelineCI.pRasterizationState || - !pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) { - VkSampleCountFlagBits psoNumSamples = getNumSamples(my_data, pipeline); - if (pCB->activeRenderPass) { - const VkRenderPassCreateInfo *pRPCI = my_data->renderPassMap[pCB->activeRenderPass]->pCreateInfo; - const VkSubpassDescription *pSD = &pRPCI->pSubpasses[pCB->activeSubpass]; - VkSampleCountFlagBits subpassNumSamples = (VkSampleCountFlagBits)0; - uint32_t i; - - for (i = 0; i < pSD->colorAttachmentCount; i++) { - VkSampleCountFlagBits samples; - - if (pSD->pColorAttachments[i].attachment == VK_ATTACHMENT_UNUSED) - continue; - - samples = pRPCI->pAttachments[pSD->pColorAttachments[i].attachment].samples; - if (subpassNumSamples == (VkSampleCountFlagBits)0) { - subpassNumSamples = samples; - } else if (subpassNumSamples != samples) { - subpassNumSamples = (VkSampleCountFlagBits)-1; - break; - } - } - if (pSD->pDepthStencilAttachment && pSD->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { - const VkSampleCountFlagBits samples = pRPCI->pAttachments[pSD->pDepthStencilAttachment->attachment].samples; - if (subpassNumSamples == (VkSampleCountFlagBits)0) - subpassNumSamples = samples; - else if (subpassNumSamples != samples) - subpassNumSamples = (VkSampleCountFlagBits)-1; - } - - if (psoNumSamples != subpassNumSamples) { - return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, - (uint64_t)pipeline, __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS", - "Num samples mismatch! Binding PSO (%#" PRIxLEAST64 - ") with %u samples while current RenderPass (%#" PRIxLEAST64 ") w/ %u samples!", - (uint64_t)pipeline, psoNumSamples, (uint64_t)pCB->activeRenderPass, subpassNumSamples); - } - } else { - // TODO : I believe it's an error if we reach this point and don't have an activeRenderPass - // Verify and flag error as appropriate - } - } - // TODO : Add more checks here - } else { - // TODO : Validate non-gfx pipeline updates - } - return VK_FALSE; -} - -// Block of code at start here specifically for managing/tracking DSs - -// Return Pool node ptr for specified pool or else NULL -static DESCRIPTOR_POOL_NODE *getPoolNode(layer_data *my_data, const VkDescriptorPool pool) { - if (my_data->descriptorPoolMap.find(pool) == my_data->descriptorPoolMap.end()) { - return NULL; - } - return my_data->descriptorPoolMap[pool]; -} - -static LAYOUT_NODE *getLayoutNode(layer_data *my_data, const VkDescriptorSetLayout layout) { - if (my_data->descriptorSetLayoutMap.find(layout) == my_data->descriptorSetLayoutMap.end()) { - return NULL; - } - return my_data->descriptorSetLayoutMap[layout]; -} - -// Return VK_FALSE if update struct is of valid type, otherwise flag error and return code from callback -static VkBool32 validUpdateStruct(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) { - switch (pUpdateStruct->sType) { - case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: - case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: - return VK_FALSE; - default: - return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_UPDATE_STRUCT, "DS", - "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", - string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType); - } -} - -// Set count for given update struct in the last parameter -// Return value of skipCall, which is only VK_TRUE if error occurs and callback signals execution to cease -static uint32_t getUpdateCount(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) { - switch (pUpdateStruct->sType) { - case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: - return ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorCount; - case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: - // TODO : Need to understand this case better and make sure code is correct - return ((VkCopyDescriptorSet *)pUpdateStruct)->descriptorCount; - default: - return 0; - } - return 0; -} - -// For given Layout Node and binding, return index where that binding begins -static uint32_t getBindingStartIndex(const LAYOUT_NODE *pLayout, const uint32_t binding) { - uint32_t offsetIndex = 0; - for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) { - if (pLayout->createInfo.pBindings[i].binding == binding) - break; - offsetIndex += pLayout->createInfo.pBindings[i].descriptorCount; - } - return offsetIndex; -} - -// For given layout node and binding, return last index that is updated -static uint32_t getBindingEndIndex(const LAYOUT_NODE *pLayout, const uint32_t binding) { - uint32_t offsetIndex = 0; - for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) { - offsetIndex += pLayout->createInfo.pBindings[i].descriptorCount; - if (pLayout->createInfo.pBindings[i].binding == binding) - break; - } - return offsetIndex - 1; -} - -// For given layout and update, return the first overall index of the layout that is updated -static uint32_t getUpdateStartIndex(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, const uint32_t binding, - const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) { - return getBindingStartIndex(pLayout, binding) + arrayIndex; -} - -// For given layout and update, return the last overall index of the layout that is updated -static uint32_t getUpdateEndIndex(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, const uint32_t binding, - const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) { - uint32_t count = getUpdateCount(my_data, device, pUpdateStruct); - return getBindingStartIndex(pLayout, binding) + arrayIndex + count - 1; -} - -// Verify that the descriptor type in the update struct matches what's expected by the layout -static VkBool32 validateUpdateConsistency(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, - const GENERIC_HEADER *pUpdateStruct, uint32_t startIndex, uint32_t endIndex) { - // First get actual type of update - VkBool32 skipCall = VK_FALSE; - VkDescriptorType actualType; - uint32_t i = 0; - switch (pUpdateStruct->sType) { - case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: - actualType = ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorType; - break; - case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: - /* no need to validate */ - return VK_FALSE; - break; - default: - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_UPDATE_STRUCT, "DS", - "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", - string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType); - } - if (VK_FALSE == skipCall) { - // Set first stageFlags as reference and verify that all other updates match it - VkShaderStageFlags refStageFlags = pLayout->stageFlags[startIndex]; - for (i = startIndex; i <= endIndex; i++) { - if (pLayout->descriptorTypes[i] != actualType) { - skipCall |= log_msg( - my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS", - "Write descriptor update has descriptor type %s that does not match overlapping binding descriptor type of %s!", - string_VkDescriptorType(actualType), string_VkDescriptorType(pLayout->descriptorTypes[i])); - } - if (pLayout->stageFlags[i] != refStageFlags) { - skipCall |= log_msg( - my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_DESCRIPTOR_STAGEFLAGS_MISMATCH, "DS", - "Write descriptor update has stageFlags %x that do not match overlapping binding descriptor stageFlags of %x!", - refStageFlags, pLayout->stageFlags[i]); - } - } - } - return skipCall; -} - -// Determine the update type, allocate a new struct of that type, shadow the given pUpdate -// struct into the pNewNode param. Return VK_TRUE if error condition encountered and callback signals early exit. -// NOTE : Calls to this function should be wrapped in mutex -static VkBool32 shadowUpdateNode(layer_data *my_data, const VkDevice device, GENERIC_HEADER *pUpdate, GENERIC_HEADER **pNewNode) { - VkBool32 skipCall = VK_FALSE; - VkWriteDescriptorSet *pWDS = NULL; - VkCopyDescriptorSet *pCDS = NULL; - switch (pUpdate->sType) { - case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: - pWDS = new VkWriteDescriptorSet; - *pNewNode = (GENERIC_HEADER *)pWDS; - memcpy(pWDS, pUpdate, sizeof(VkWriteDescriptorSet)); - - switch (pWDS->descriptorType) { - case VK_DESCRIPTOR_TYPE_SAMPLER: - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { - VkDescriptorImageInfo *info = new VkDescriptorImageInfo[pWDS->descriptorCount]; - memcpy(info, pWDS->pImageInfo, pWDS->descriptorCount * sizeof(VkDescriptorImageInfo)); - pWDS->pImageInfo = info; - } break; - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { - VkBufferView *info = new VkBufferView[pWDS->descriptorCount]; - memcpy(info, pWDS->pTexelBufferView, pWDS->descriptorCount * sizeof(VkBufferView)); - pWDS->pTexelBufferView = info; - } break; - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { - VkDescriptorBufferInfo *info = new VkDescriptorBufferInfo[pWDS->descriptorCount]; - memcpy(info, pWDS->pBufferInfo, pWDS->descriptorCount * sizeof(VkDescriptorBufferInfo)); - pWDS->pBufferInfo = info; - } break; - default: - return VK_ERROR_VALIDATION_FAILED_EXT; - break; - } - break; - case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: - pCDS = new VkCopyDescriptorSet; - *pNewNode = (GENERIC_HEADER *)pCDS; - memcpy(pCDS, pUpdate, sizeof(VkCopyDescriptorSet)); - break; - default: - if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_UPDATE_STRUCT, "DS", - "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", - string_VkStructureType(pUpdate->sType), pUpdate->sType)) - return VK_TRUE; - } - // Make sure that pNext for the end of shadow copy is NULL - (*pNewNode)->pNext = NULL; - return skipCall; -} - -// Verify that given sampler is valid -static VkBool32 validateSampler(const layer_data *my_data, const VkSampler *pSampler, const VkBool32 immutable) { - VkBool32 skipCall = VK_FALSE; - auto sampIt = my_data->sampleMap.find(*pSampler); - if (sampIt == my_data->sampleMap.end()) { - if (!immutable) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, - (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS", - "vkUpdateDescriptorSets: Attempt to update descriptor with invalid sampler %#" PRIxLEAST64, - (uint64_t)*pSampler); - } else { // immutable - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, - (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS", - "vkUpdateDescriptorSets: Attempt to update descriptor whose binding has an invalid immutable " - "sampler %#" PRIxLEAST64, - (uint64_t)*pSampler); - } - } else { - // TODO : Any further checks we want to do on the sampler? - } - return skipCall; -} - -// find layout(s) on the cmd buf level -bool FindLayout(const GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, IMAGE_CMD_BUF_LAYOUT_NODE &node) { - ImageSubresourcePair imgpair = {image, true, range}; - auto imgsubIt = pCB->imageLayoutMap.find(imgpair); - if (imgsubIt == pCB->imageLayoutMap.end()) { - imgpair = {image, false, VkImageSubresource()}; - imgsubIt = pCB->imageLayoutMap.find(imgpair); - if (imgsubIt == pCB->imageLayoutMap.end()) - return false; - } - node = imgsubIt->second; - return true; -} - -// find layout(s) on the global level -bool FindLayout(const layer_data *my_data, ImageSubresourcePair imgpair, VkImageLayout &layout) { - auto imgsubIt = my_data->imageLayoutMap.find(imgpair); - if (imgsubIt == my_data->imageLayoutMap.end()) { - imgpair = {imgpair.image, false, VkImageSubresource()}; - imgsubIt = my_data->imageLayoutMap.find(imgpair); - if (imgsubIt == my_data->imageLayoutMap.end()) - return false; - } - layout = imgsubIt->second.layout; - return true; -} - -bool FindLayout(const layer_data *my_data, VkImage image, VkImageSubresource range, VkImageLayout &layout) { - ImageSubresourcePair imgpair = {image, true, range}; - return FindLayout(my_data, imgpair, layout); -} - -bool FindLayouts(const layer_data *my_data, VkImage image, std::vector<VkImageLayout> &layouts) { - auto sub_data = my_data->imageSubresourceMap.find(image); - if (sub_data == my_data->imageSubresourceMap.end()) - return false; - auto imgIt = my_data->imageMap.find(image); - if (imgIt == my_data->imageMap.end()) - return false; - bool ignoreGlobal = false; - // TODO: Make this robust for >1 aspect mask. Now it will just say ignore - // potential errors in this case. - if (sub_data->second.size() >= (imgIt->second.createInfo.arrayLayers * imgIt->second.createInfo.mipLevels + 1)) { - ignoreGlobal = true; - } - for (auto imgsubpair : sub_data->second) { - if (ignoreGlobal && !imgsubpair.hasSubresource) - continue; - auto img_data = my_data->imageLayoutMap.find(imgsubpair); - if (img_data != my_data->imageLayoutMap.end()) { - layouts.push_back(img_data->second.layout); - } - } - return true; -} - -// Set the layout on the global level -void SetLayout(layer_data *my_data, ImageSubresourcePair imgpair, const VkImageLayout &layout) { - VkImage &image = imgpair.image; - // TODO (mlentine): Maybe set format if new? Not used atm. - my_data->imageLayoutMap[imgpair].layout = layout; - // TODO (mlentine): Maybe make vector a set? - auto subresource = std::find(my_data->imageSubresourceMap[image].begin(), my_data->imageSubresourceMap[image].end(), imgpair); - if (subresource == my_data->imageSubresourceMap[image].end()) { - my_data->imageSubresourceMap[image].push_back(imgpair); - } -} - -void SetLayout(layer_data *my_data, VkImage image, const VkImageLayout &layout) { - ImageSubresourcePair imgpair = {image, false, VkImageSubresource()}; - SetLayout(my_data, imgpair, layout); -} - -void SetLayout(layer_data *my_data, VkImage image, VkImageSubresource range, const VkImageLayout &layout) { - ImageSubresourcePair imgpair = {image, true, range}; - SetLayout(my_data, imgpair, layout); -} - -// Set the layout on the cmdbuf level -void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node) { - pCB->imageLayoutMap[imgpair] = node; - // TODO (mlentine): Maybe make vector a set? - auto subresource = std::find(pCB->imageSubresourceMap[image].begin(), pCB->imageSubresourceMap[image].end(), imgpair); - if (subresource == pCB->imageSubresourceMap[image].end()) { - pCB->imageSubresourceMap[image].push_back(imgpair); - } -} - -void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, ImageSubresourcePair imgpair, const VkImageLayout &layout) { - // TODO (mlentine): Maybe make vector a set? - if (std::find(pCB->imageSubresourceMap[image].begin(), pCB->imageSubresourceMap[image].end(), imgpair) != - pCB->imageSubresourceMap[image].end()) { - pCB->imageLayoutMap[imgpair].layout = layout; - } else { - // TODO (mlentine): Could be expensive and might need to be removed. - assert(imgpair.hasSubresource); - IMAGE_CMD_BUF_LAYOUT_NODE node; - FindLayout(pCB, image, imgpair.subresource, node); - SetLayout(pCB, image, imgpair, {node.initialLayout, layout}); - } -} - -void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, const IMAGE_CMD_BUF_LAYOUT_NODE &node) { - ImageSubresourcePair imgpair = {image, false, VkImageSubresource()}; - SetLayout(pCB, image, imgpair, node); -} - -void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, const IMAGE_CMD_BUF_LAYOUT_NODE &node) { - ImageSubresourcePair imgpair = {image, true, range}; - SetLayout(pCB, image, imgpair, node); -} - -void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, const VkImageLayout &layout) { - ImageSubresourcePair imgpair = {image, false, VkImageSubresource()}; - SetLayout(pCB, image, imgpair, layout); -} - -void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, const VkImageLayout &layout) { - ImageSubresourcePair imgpair = {image, true, range}; - SetLayout(pCB, image, imgpair, layout); -} - -void SetLayout(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkImageView imageView, const VkImageLayout &layout) { - auto image_view_data = dev_data->imageViewMap.find(imageView); - assert(image_view_data != dev_data->imageViewMap.end()); - const VkImage &image = image_view_data->second->image; - const VkImageSubresourceRange &subRange = image_view_data->second->subresourceRange; - // TODO: Do not iterate over every possibility - consolidate where possible - for (uint32_t j = 0; j < subRange.levelCount; j++) { - uint32_t level = subRange.baseMipLevel + j; - for (uint32_t k = 0; k < subRange.layerCount; k++) { - uint32_t layer = subRange.baseArrayLayer + k; - VkImageSubresource sub = {subRange.aspectMask, level, layer}; - SetLayout(pCB, image, sub, layout); - } - } -} - -// Verify that given imageView is valid -static VkBool32 validateImageView(const layer_data *my_data, const VkImageView *pImageView, const VkImageLayout imageLayout) { - VkBool32 skipCall = VK_FALSE; - auto ivIt = my_data->imageViewMap.find(*pImageView); - if (ivIt == my_data->imageViewMap.end()) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, - (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", - "vkUpdateDescriptorSets: Attempt to update descriptor with invalid imageView %#" PRIxLEAST64, - (uint64_t)*pImageView); - } else { - // Validate that imageLayout is compatible with aspectMask and image format - VkImageAspectFlags aspectMask = ivIt->second->subresourceRange.aspectMask; - VkImage image = ivIt->second->image; - // TODO : Check here in case we have a bad image - VkFormat format = VK_FORMAT_MAX_ENUM; - auto imgIt = my_data->imageMap.find(image); - if (imgIt != my_data->imageMap.end()) { - format = (*imgIt).second.createInfo.format; - } else { - // Also need to check the swapchains. - auto swapchainIt = my_data->device_extensions.imageToSwapchainMap.find(image); - if (swapchainIt != my_data->device_extensions.imageToSwapchainMap.end()) { - VkSwapchainKHR swapchain = swapchainIt->second; - auto swapchain_nodeIt = my_data->device_extensions.swapchainMap.find(swapchain); - if (swapchain_nodeIt != my_data->device_extensions.swapchainMap.end()) { - SWAPCHAIN_NODE *pswapchain_node = swapchain_nodeIt->second; - format = pswapchain_node->createInfo.imageFormat; - } - } - } - if (format == VK_FORMAT_MAX_ENUM) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - (uint64_t)image, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", - "vkUpdateDescriptorSets: Attempt to update descriptor with invalid image %#" PRIxLEAST64 - " in imageView %#" PRIxLEAST64, - (uint64_t)image, (uint64_t)*pImageView); - } else { - VkBool32 ds = vk_format_is_depth_or_stencil(format); - switch (imageLayout) { - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - // Only Color bit must be set - if ((aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, - (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS", - "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL " - "and imageView %#" PRIxLEAST64 "" - " that does not have VK_IMAGE_ASPECT_COLOR_BIT set.", - (uint64_t)*pImageView); - } - // format must NOT be DS - if (ds) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, - (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", - "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL " - "and imageView %#" PRIxLEAST64 "" - " but the image format is %s which is not a color format.", - (uint64_t)*pImageView, string_VkFormat(format)); - } - break; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: - // Depth or stencil bit must be set, but both must NOT be set - if (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) { - if (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) { - // both must NOT be set - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, - (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS", - "vkUpdateDescriptorSets: Updating descriptor with imageView %#" PRIxLEAST64 "" - " that has both STENCIL and DEPTH aspects set", - (uint64_t)*pImageView); - } - } else if (!(aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) { - // Neither were set - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, - (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS", - "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 "" - " that does not have STENCIL or DEPTH aspect set.", - string_VkImageLayout(imageLayout), (uint64_t)*pImageView); - } - // format must be DS - if (!ds) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, - (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS", - "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 "" - " but the image format is %s which is not a depth/stencil format.", - string_VkImageLayout(imageLayout), (uint64_t)*pImageView, string_VkFormat(format)); - } - break; - default: - // anything to check for other layouts? - break; - } - } - } - return skipCall; -} - -// Verify that given bufferView is valid -static VkBool32 validateBufferView(const layer_data *my_data, const VkBufferView *pBufferView) { - VkBool32 skipCall = VK_FALSE; - auto sampIt = my_data->bufferViewMap.find(*pBufferView); - if (sampIt == my_data->bufferViewMap.end()) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT, - (uint64_t)*pBufferView, __LINE__, DRAWSTATE_BUFFERVIEW_DESCRIPTOR_ERROR, "DS", - "vkUpdateDescriptorSets: Attempt to update descriptor with invalid bufferView %#" PRIxLEAST64, - (uint64_t)*pBufferView); - } else { - // TODO : Any further checks we want to do on the bufferView? - } - return skipCall; -} - -// Verify that given bufferInfo is valid -static VkBool32 validateBufferInfo(const layer_data *my_data, const VkDescriptorBufferInfo *pBufferInfo) { - VkBool32 skipCall = VK_FALSE; - auto sampIt = my_data->bufferMap.find(pBufferInfo->buffer); - if (sampIt == my_data->bufferMap.end()) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, - (uint64_t)pBufferInfo->buffer, __LINE__, DRAWSTATE_BUFFERINFO_DESCRIPTOR_ERROR, "DS", - "vkUpdateDescriptorSets: Attempt to update descriptor where bufferInfo has invalid buffer %#" PRIxLEAST64, - (uint64_t)pBufferInfo->buffer); - } else { - // TODO : Any further checks we want to do on the bufferView? - } - return skipCall; -} - -static VkBool32 validateUpdateContents(const layer_data *my_data, const VkWriteDescriptorSet *pWDS, - const VkDescriptorSetLayoutBinding *pLayoutBinding) { - VkBool32 skipCall = VK_FALSE; - // First verify that for the given Descriptor type, the correct DescriptorInfo data is supplied - const VkSampler *pSampler = NULL; - VkBool32 immutable = VK_FALSE; - uint32_t i = 0; - // For given update type, verify that update contents are correct - switch (pWDS->descriptorType) { - case VK_DESCRIPTOR_TYPE_SAMPLER: - for (i = 0; i < pWDS->descriptorCount; ++i) { - skipCall |= validateSampler(my_data, &(pWDS->pImageInfo[i].sampler), immutable); - } - break; - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - for (i = 0; i < pWDS->descriptorCount; ++i) { - if (NULL == pLayoutBinding->pImmutableSamplers) { - pSampler = &(pWDS->pImageInfo[i].sampler); - if (immutable) { - skipCall |= log_msg( - my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, - (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS", - "vkUpdateDescriptorSets: Update #%u is not an immutable sampler %#" PRIxLEAST64 - ", but previous update(s) from this " - "VkWriteDescriptorSet struct used an immutable sampler. All updates from a single struct must either " - "use immutable or non-immutable samplers.", - i, (uint64_t)*pSampler); - } - } else { - if (i > 0 && !immutable) { - skipCall |= log_msg( - my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, - (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS", - "vkUpdateDescriptorSets: Update #%u is an immutable sampler, but previous update(s) from this " - "VkWriteDescriptorSet struct used a non-immutable sampler. All updates from a single struct must either " - "use immutable or non-immutable samplers.", - i); - } - immutable = VK_TRUE; - pSampler = &(pLayoutBinding->pImmutableSamplers[i]); - } - skipCall |= validateSampler(my_data, pSampler, immutable); - } - // Intentionally fall through here to also validate image stuff - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: - for (i = 0; i < pWDS->descriptorCount; ++i) { - skipCall |= validateImageView(my_data, &(pWDS->pImageInfo[i].imageView), pWDS->pImageInfo[i].imageLayout); - } - break; - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - for (i = 0; i < pWDS->descriptorCount; ++i) { - skipCall |= validateBufferView(my_data, &(pWDS->pTexelBufferView[i])); - } - break; - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: - for (i = 0; i < pWDS->descriptorCount; ++i) { - skipCall |= validateBufferInfo(my_data, &(pWDS->pBufferInfo[i])); - } - break; - default: - break; - } - return skipCall; -} -// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer -// func_str is the name of the calling function -// Return VK_FALSE if no errors occur -// Return VK_TRUE if validation error occurs and callback returns VK_TRUE (to skip upcoming API call down the chain) -VkBool32 validateIdleDescriptorSet(const layer_data *my_data, VkDescriptorSet set, std::string func_str) { - VkBool32 skip_call = VK_FALSE; - auto set_node = my_data->setMap.find(set); - if (set_node == my_data->setMap.end()) { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - (uint64_t)(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS", - "Cannot call %s() on descriptor set %" PRIxLEAST64 " that has not been allocated.", func_str.c_str(), - (uint64_t)(set)); - } else { - if (set_node->second->in_use.load()) { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)(set), __LINE__, DRAWSTATE_OBJECT_INUSE, - "DS", "Cannot call %s() on descriptor set %" PRIxLEAST64 " that is in use by a command buffer.", - func_str.c_str(), (uint64_t)(set)); - } - } - return skip_call; -} -static void invalidateBoundCmdBuffers(layer_data *dev_data, const SET_NODE *pSet) { - // Flag any CBs this set is bound to as INVALID - for (auto cb : pSet->boundCmdBuffers) { - auto cb_node = dev_data->commandBufferMap.find(cb); - if (cb_node != dev_data->commandBufferMap.end()) { - cb_node->second->state = CB_INVALID; - } - } -} -// update DS mappings based on write and copy update arrays -static VkBool32 dsUpdate(layer_data *my_data, VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pWDS, - uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pCDS) { - VkBool32 skipCall = VK_FALSE; - - LAYOUT_NODE *pLayout = NULL; - VkDescriptorSetLayoutCreateInfo *pLayoutCI = NULL; - // Validate Write updates - uint32_t i = 0; - for (i = 0; i < descriptorWriteCount; i++) { - VkDescriptorSet ds = pWDS[i].dstSet; - SET_NODE *pSet = my_data->setMap[ds]; - // Set being updated cannot be in-flight - if ((skipCall = validateIdleDescriptorSet(my_data, ds, "VkUpdateDescriptorSets")) == VK_TRUE) - return skipCall; - // If set is bound to any cmdBuffers, mark them invalid - invalidateBoundCmdBuffers(my_data, pSet); - GENERIC_HEADER *pUpdate = (GENERIC_HEADER *)&pWDS[i]; - pLayout = pSet->pLayout; - // First verify valid update struct - if ((skipCall = validUpdateStruct(my_data, device, pUpdate)) == VK_TRUE) { - break; - } - uint32_t binding = 0, endIndex = 0; - binding = pWDS[i].dstBinding; - auto bindingToIndex = pLayout->bindingToIndexMap.find(binding); - // Make sure that layout being updated has the binding being updated - if (bindingToIndex == pLayout->bindingToIndexMap.end()) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - (uint64_t)(ds), __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS", - "Descriptor Set %" PRIu64 " does not have binding to match " - "update binding %u for update type " - "%s!", - (uint64_t)(ds), binding, string_VkStructureType(pUpdate->sType)); - } else { - // Next verify that update falls within size of given binding - endIndex = getUpdateEndIndex(my_data, device, pLayout, binding, pWDS[i].dstArrayElement, pUpdate); - if (getBindingEndIndex(pLayout, binding) < endIndex) { - pLayoutCI = &pLayout->createInfo; - string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS} "); - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - (uint64_t)(ds), __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS", - "Descriptor update type of %s is out of bounds for matching binding %u in Layout w/ CI:\n%s!", - string_VkStructureType(pUpdate->sType), binding, DSstr.c_str()); - } else { // TODO : should we skip update on a type mismatch or force it? - uint32_t startIndex; - startIndex = getUpdateStartIndex(my_data, device, pLayout, binding, pWDS[i].dstArrayElement, pUpdate); - // Layout bindings match w/ update, now verify that update type - // & stageFlags are the same for entire update - if ((skipCall = validateUpdateConsistency(my_data, device, pLayout, pUpdate, startIndex, endIndex)) == VK_FALSE) { - // The update is within bounds and consistent, but need to - // make sure contents make sense as well - if ((skipCall = validateUpdateContents(my_data, &pWDS[i], - &pLayout->createInfo.pBindings[bindingToIndex->second])) == VK_FALSE) { - // Update is good. Save the update info - // Create new update struct for this set's shadow copy - GENERIC_HEADER *pNewNode = NULL; - skipCall |= shadowUpdateNode(my_data, device, pUpdate, &pNewNode); - if (NULL == pNewNode) { - skipCall |= log_msg( - my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - (uint64_t)(ds), __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", - "Out of memory while attempting to allocate UPDATE struct in vkUpdateDescriptors()"); - } else { - // Insert shadow node into LL of updates for this set - pNewNode->pNext = pSet->pUpdateStructs; - pSet->pUpdateStructs = pNewNode; - // Now update appropriate descriptor(s) to point to new Update node - for (uint32_t j = startIndex; j <= endIndex; j++) { - assert(j < pSet->descriptorCount); - pSet->ppDescriptors[j] = pNewNode; - } - } - } - } - } - } - } - // Now validate copy updates - for (i = 0; i < descriptorCopyCount; ++i) { - SET_NODE *pSrcSet = NULL, *pDstSet = NULL; - LAYOUT_NODE *pSrcLayout = NULL, *pDstLayout = NULL; - uint32_t srcStartIndex = 0, srcEndIndex = 0, dstStartIndex = 0, dstEndIndex = 0; - // For each copy make sure that update falls within given layout and that types match - pSrcSet = my_data->setMap[pCDS[i].srcSet]; - pDstSet = my_data->setMap[pCDS[i].dstSet]; - // Set being updated cannot be in-flight - if ((skipCall = validateIdleDescriptorSet(my_data, pDstSet->set, "VkUpdateDescriptorSets")) == VK_TRUE) - return skipCall; - invalidateBoundCmdBuffers(my_data, pDstSet); - pSrcLayout = pSrcSet->pLayout; - pDstLayout = pDstSet->pLayout; - // Validate that src binding is valid for src set layout - if (pSrcLayout->bindingToIndexMap.find(pCDS[i].srcBinding) == pSrcLayout->bindingToIndexMap.end()) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS", - "Copy descriptor update %u has srcBinding %u " - "which is out of bounds for underlying SetLayout " - "%#" PRIxLEAST64 " which only has bindings 0-%u.", - i, pCDS[i].srcBinding, (uint64_t)pSrcLayout->layout, pSrcLayout->createInfo.bindingCount - 1); - } else if (pDstLayout->bindingToIndexMap.find(pCDS[i].dstBinding) == pDstLayout->bindingToIndexMap.end()) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS", - "Copy descriptor update %u has dstBinding %u " - "which is out of bounds for underlying SetLayout " - "%#" PRIxLEAST64 " which only has bindings 0-%u.", - i, pCDS[i].dstBinding, (uint64_t)pDstLayout->layout, pDstLayout->createInfo.bindingCount - 1); - } else { - // Proceed with validation. Bindings are ok, but make sure update is within bounds of given layout - srcEndIndex = getUpdateEndIndex(my_data, device, pSrcLayout, pCDS[i].srcBinding, pCDS[i].srcArrayElement, - (const GENERIC_HEADER *)&(pCDS[i])); - dstEndIndex = getUpdateEndIndex(my_data, device, pDstLayout, pCDS[i].dstBinding, pCDS[i].dstArrayElement, - (const GENERIC_HEADER *)&(pCDS[i])); - if (getBindingEndIndex(pSrcLayout, pCDS[i].srcBinding) < srcEndIndex) { - pLayoutCI = &pSrcLayout->createInfo; - string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS} "); - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS", - "Copy descriptor src update is out of bounds for matching binding %u in Layout w/ CI:\n%s!", - pCDS[i].srcBinding, DSstr.c_str()); - } else if (getBindingEndIndex(pDstLayout, pCDS[i].dstBinding) < dstEndIndex) { - pLayoutCI = &pDstLayout->createInfo; - string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS} "); - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS", - "Copy descriptor dest update is out of bounds for matching binding %u in Layout w/ CI:\n%s!", - pCDS[i].dstBinding, DSstr.c_str()); - } else { - srcStartIndex = getUpdateStartIndex(my_data, device, pSrcLayout, pCDS[i].srcBinding, pCDS[i].srcArrayElement, - (const GENERIC_HEADER *)&(pCDS[i])); - dstStartIndex = getUpdateStartIndex(my_data, device, pDstLayout, pCDS[i].dstBinding, pCDS[i].dstArrayElement, - (const GENERIC_HEADER *)&(pCDS[i])); - for (uint32_t j = 0; j < pCDS[i].descriptorCount; ++j) { - // For copy just make sure that the types match and then perform the update - if (pSrcLayout->descriptorTypes[srcStartIndex + j] != pDstLayout->descriptorTypes[dstStartIndex + j]) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS", - "Copy descriptor update index %u, update count #%u, has src update descriptor type %s " - "that does not match overlapping dest descriptor type of %s!", - i, j + 1, string_VkDescriptorType(pSrcLayout->descriptorTypes[srcStartIndex + j]), - string_VkDescriptorType(pDstLayout->descriptorTypes[dstStartIndex + j])); - } else { - // point dst descriptor at corresponding src descriptor - // TODO : This may be a hole. I believe copy should be its own copy, - // otherwise a subsequent write update to src will incorrectly affect the copy - pDstSet->ppDescriptors[j + dstStartIndex] = pSrcSet->ppDescriptors[j + srcStartIndex]; - pDstSet->pUpdateStructs = pSrcSet->pUpdateStructs; - } - } - } - } - } - return skipCall; -} - -// Verify that given pool has descriptors that are being requested for allocation -static VkBool32 validate_descriptor_availability_in_pool(layer_data *dev_data, DESCRIPTOR_POOL_NODE *pPoolNode, uint32_t count, - const VkDescriptorSetLayout *pSetLayouts) { - VkBool32 skipCall = VK_FALSE; - uint32_t i = 0, j = 0; - for (i = 0; i < count; ++i) { - LAYOUT_NODE *pLayout = getLayoutNode(dev_data, pSetLayouts[i]); - if (NULL == pLayout) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, - (uint64_t)pSetLayouts[i], __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS", - "Unable to find set layout node for layout %#" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call", - (uint64_t)pSetLayouts[i]); - } else { - uint32_t typeIndex = 0, poolSizeCount = 0; - for (j = 0; j < pLayout->createInfo.bindingCount; ++j) { - typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBindings[j].descriptorType); - poolSizeCount = pLayout->createInfo.pBindings[j].descriptorCount; - if (poolSizeCount > pPoolNode->availableDescriptorTypeCount[typeIndex]) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pLayout->layout, __LINE__, - DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS", - "Unable to allocate %u descriptors of type %s from pool %#" PRIxLEAST64 - ". This pool only has %u descriptors of this type remaining.", - poolSizeCount, string_VkDescriptorType(pLayout->createInfo.pBindings[j].descriptorType), - (uint64_t)pPoolNode->pool, pPoolNode->availableDescriptorTypeCount[typeIndex]); - } else { // Decrement available descriptors of this type - pPoolNode->availableDescriptorTypeCount[typeIndex] -= poolSizeCount; - } - } - } - } - return skipCall; -} - -// Free the shadowed update node for this Set -// NOTE : Calls to this function should be wrapped in mutex -static void freeShadowUpdateTree(SET_NODE *pSet) { - GENERIC_HEADER *pShadowUpdate = pSet->pUpdateStructs; - pSet->pUpdateStructs = NULL; - GENERIC_HEADER *pFreeUpdate = pShadowUpdate; - // Clear the descriptor mappings as they will now be invalid - memset(pSet->ppDescriptors, 0, pSet->descriptorCount * sizeof(GENERIC_HEADER *)); - while (pShadowUpdate) { - pFreeUpdate = pShadowUpdate; - pShadowUpdate = (GENERIC_HEADER *)pShadowUpdate->pNext; - VkWriteDescriptorSet *pWDS = NULL; - switch (pFreeUpdate->sType) { - case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: - pWDS = (VkWriteDescriptorSet *)pFreeUpdate; - switch (pWDS->descriptorType) { - case VK_DESCRIPTOR_TYPE_SAMPLER: - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { - delete[] pWDS->pImageInfo; - } break; - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { - delete[] pWDS->pTexelBufferView; - } break; - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { - delete[] pWDS->pBufferInfo; - } break; - default: - break; - } - break; - case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: - break; - default: - assert(0); - break; - } - delete pFreeUpdate; - } -} - -// Free all DS Pools including their Sets & related sub-structs -// NOTE : Calls to this function should be wrapped in mutex -static void deletePools(layer_data *my_data) { - if (my_data->descriptorPoolMap.size() <= 0) - return; - for (auto ii = my_data->descriptorPoolMap.begin(); ii != my_data->descriptorPoolMap.end(); ++ii) { - SET_NODE *pSet = (*ii).second->pSets; - SET_NODE *pFreeSet = pSet; - while (pSet) { - pFreeSet = pSet; - pSet = pSet->pNext; - // Freeing layouts handled in deleteLayouts() function - // Free Update shadow struct tree - freeShadowUpdateTree(pFreeSet); - delete[] pFreeSet->ppDescriptors; - delete pFreeSet; - } - delete (*ii).second; - } - my_data->descriptorPoolMap.clear(); -} - -// WARN : Once deleteLayouts() called, any layout ptrs in Pool/Set data structure will be invalid -// NOTE : Calls to this function should be wrapped in mutex -static void deleteLayouts(layer_data *my_data) { - if (my_data->descriptorSetLayoutMap.size() <= 0) - return; - for (auto ii = my_data->descriptorSetLayoutMap.begin(); ii != my_data->descriptorSetLayoutMap.end(); ++ii) { - LAYOUT_NODE *pLayout = (*ii).second; - if (pLayout->createInfo.pBindings) { - for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) { - delete[] pLayout->createInfo.pBindings[i].pImmutableSamplers; - } - delete[] pLayout->createInfo.pBindings; - } - delete pLayout; - } - my_data->descriptorSetLayoutMap.clear(); -} - -// Currently clearing a set is removing all previous updates to that set -// TODO : Validate if this is correct clearing behavior -static void clearDescriptorSet(layer_data *my_data, VkDescriptorSet set) { - SET_NODE *pSet = getSetNode(my_data, set); - if (!pSet) { - // TODO : Return error - } else { - freeShadowUpdateTree(pSet); - } -} - -static void clearDescriptorPool(layer_data *my_data, const VkDevice device, const VkDescriptorPool pool, - VkDescriptorPoolResetFlags flags) { - DESCRIPTOR_POOL_NODE *pPool = getPoolNode(my_data, pool); - if (!pPool) { - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, - (uint64_t)pool, __LINE__, DRAWSTATE_INVALID_POOL, "DS", - "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkResetDescriptorPool() call", (uint64_t)pool); - } else { - // TODO: validate flags - // For every set off of this pool, clear it - SET_NODE *pSet = pPool->pSets; - while (pSet) { - clearDescriptorSet(my_data, pSet->set); - pSet = pSet->pNext; - } - // Reset available count to max count for this pool - for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) { - pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i]; - } - } -} - -// For given CB object, fetch associated CB Node from map -static GLOBAL_CB_NODE *getCBNode(layer_data *my_data, const VkCommandBuffer cb) { - if (my_data->commandBufferMap.count(cb) == 0) { - // TODO : How to pass cb as srcObj here? - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, - DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", "Attempt to use CommandBuffer %#" PRIxLEAST64 " that doesn't exist!", - (uint64_t)(cb)); - return NULL; - } - return my_data->commandBufferMap[cb]; -} - -// Free all CB Nodes -// NOTE : Calls to this function should be wrapped in mutex -static void deleteCommandBuffers(layer_data *my_data) { - if (my_data->commandBufferMap.size() <= 0) { - return; - } - for (auto ii = my_data->commandBufferMap.begin(); ii != my_data->commandBufferMap.end(); ++ii) { - delete (*ii).second; - } - my_data->commandBufferMap.clear(); -} - -static VkBool32 report_error_no_cb_begin(const layer_data *dev_data, const VkCommandBuffer cb, const char *caller_name) { - return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)cb, __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS", - "You must call vkBeginCommandBuffer() before this call to %s", caller_name); -} - -VkBool32 validateCmdsInCmdBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) { - if (!pCB->activeRenderPass) - return VK_FALSE; - VkBool32 skip_call = VK_FALSE; - if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS && cmd_type != CMD_EXECUTECOMMANDS) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", - "Commands cannot be called in a subpass using secondary command buffers."); - } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", - "vkCmdExecuteCommands() cannot be called in a subpass using inline commands."); - } - return skip_call; -} - -static bool checkGraphicsBit(const layer_data *my_data, VkQueueFlags flags, const char *name) { - if (!(flags & VK_QUEUE_GRAPHICS_BIT)) - return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", - "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name); - return false; -} - -static bool checkComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) { - if (!(flags & VK_QUEUE_COMPUTE_BIT)) - return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", - "Cannot call %s on a command buffer allocated from a pool without compute capabilities.", name); - return false; -} - -static bool checkGraphicsOrComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) { - if (!((flags & VK_QUEUE_GRAPHICS_BIT) || (flags & VK_QUEUE_COMPUTE_BIT))) - return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", - "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name); - return false; -} - -// Add specified CMD to the CmdBuffer in given pCB, flagging errors if CB is not -// in the recording state or if there's an issue with the Cmd ordering -static VkBool32 addCmd(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name) { - VkBool32 skipCall = VK_FALSE; - auto pool_data = my_data->commandPoolMap.find(pCB->createInfo.commandPool); - if (pool_data != my_data->commandPoolMap.end()) { - VkQueueFlags flags = my_data->physDevProperties.queue_family_properties[pool_data->second.queueFamilyIndex].queueFlags; - switch (cmd) { - case CMD_BINDPIPELINE: - case CMD_BINDPIPELINEDELTA: - case CMD_BINDDESCRIPTORSETS: - case CMD_FILLBUFFER: - case CMD_CLEARCOLORIMAGE: - case CMD_SETEVENT: - case CMD_RESETEVENT: - case CMD_WAITEVENTS: - case CMD_BEGINQUERY: - case CMD_ENDQUERY: - case CMD_RESETQUERYPOOL: - case CMD_COPYQUERYPOOLRESULTS: - case CMD_WRITETIMESTAMP: - skipCall |= checkGraphicsOrComputeBit(my_data, flags, cmdTypeToString(cmd).c_str()); - break; - case CMD_SETVIEWPORTSTATE: - case CMD_SETSCISSORSTATE: - case CMD_SETLINEWIDTHSTATE: - case CMD_SETDEPTHBIASSTATE: - case CMD_SETBLENDSTATE: - case CMD_SETDEPTHBOUNDSSTATE: - case CMD_SETSTENCILREADMASKSTATE: - case CMD_SETSTENCILWRITEMASKSTATE: - case CMD_SETSTENCILREFERENCESTATE: - case CMD_BINDINDEXBUFFER: - case CMD_BINDVERTEXBUFFER: - case CMD_DRAW: - case CMD_DRAWINDEXED: - case CMD_DRAWINDIRECT: - case CMD_DRAWINDEXEDINDIRECT: - case CMD_BLITIMAGE: - case CMD_CLEARATTACHMENTS: - case CMD_CLEARDEPTHSTENCILIMAGE: - case CMD_RESOLVEIMAGE: - case CMD_BEGINRENDERPASS: - case CMD_NEXTSUBPASS: - case CMD_ENDRENDERPASS: - skipCall |= checkGraphicsBit(my_data, flags, cmdTypeToString(cmd).c_str()); - break; - case CMD_DISPATCH: - case CMD_DISPATCHINDIRECT: - skipCall |= checkComputeBit(my_data, flags, cmdTypeToString(cmd).c_str()); - break; - case CMD_COPYBUFFER: - case CMD_COPYIMAGE: - case CMD_COPYBUFFERTOIMAGE: - case CMD_COPYIMAGETOBUFFER: - case CMD_CLONEIMAGEDATA: - case CMD_UPDATEBUFFER: - case CMD_PIPELINEBARRIER: - case CMD_EXECUTECOMMANDS: - break; - default: - break; - } - } - if (pCB->state != CB_RECORDING) { - skipCall |= report_error_no_cb_begin(my_data, pCB->commandBuffer, caller_name); - skipCall |= validateCmdsInCmdBuffer(my_data, pCB, cmd); - CMD_NODE cmdNode = {}; - // init cmd node and append to end of cmd LL - cmdNode.cmdNumber = ++pCB->numCmds; - cmdNode.type = cmd; - pCB->cmds.push_back(cmdNode); - } - return skipCall; -} -// Reset the command buffer state -// Maintain the createInfo and set state to CB_NEW, but clear all other state -static void resetCB(layer_data *my_data, const VkCommandBuffer cb) { - GLOBAL_CB_NODE *pCB = my_data->commandBufferMap[cb]; - if (pCB) { - pCB->cmds.clear(); - // Reset CB state (note that createInfo is not cleared) - pCB->commandBuffer = cb; - memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo)); - memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo)); - pCB->fence = 0; - pCB->numCmds = 0; - memset(pCB->drawCount, 0, NUM_DRAW_TYPES * sizeof(uint64_t)); - pCB->state = CB_NEW; - pCB->submitCount = 0; - pCB->status = 0; - pCB->lastBoundPipeline = 0; - pCB->lastVtxBinding = 0; - pCB->boundVtxBuffers.clear(); - pCB->viewports.clear(); - pCB->scissors.clear(); - pCB->lineWidth = 0; - pCB->depthBiasConstantFactor = 0; - pCB->depthBiasClamp = 0; - pCB->depthBiasSlopeFactor = 0; - memset(pCB->blendConstants, 0, 4 * sizeof(float)); - pCB->minDepthBounds = 0; - pCB->maxDepthBounds = 0; - memset(&pCB->front, 0, sizeof(stencil_data)); - memset(&pCB->back, 0, sizeof(stencil_data)); - pCB->lastBoundDescriptorSet = 0; - pCB->lastBoundPipelineLayout = 0; - memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo)); - pCB->activeRenderPass = 0; - pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE; - pCB->activeSubpass = 0; - pCB->framebuffer = 0; - // Before clearing uniqueBoundSets, remove this CB off of its boundCBs - for (auto set : pCB->uniqueBoundSets) { - auto set_node = my_data->setMap.find(set); - if (set_node != my_data->setMap.end()) { - set_node->second->boundCmdBuffers.erase(pCB->commandBuffer); - } - } - pCB->uniqueBoundSets.clear(); - pCB->destroyedSets.clear(); - pCB->updatedSets.clear(); - pCB->destroyedFramebuffers.clear(); - pCB->boundDescriptorSets.clear(); - pCB->waitedEvents.clear(); - pCB->semaphores.clear(); - pCB->events.clear(); - pCB->waitedEventsBeforeQueryReset.clear(); - pCB->queryToStateMap.clear(); - pCB->activeQueries.clear(); - pCB->startedQueries.clear(); - pCB->imageLayoutMap.clear(); - pCB->eventToStageMap.clear(); - pCB->drawData.clear(); - pCB->currentDrawData.buffers.clear(); - pCB->primaryCommandBuffer = VK_NULL_HANDLE; - pCB->secondaryCommandBuffers.clear(); - pCB->dynamicOffsets.clear(); - } -} - -// Set PSO-related status bits for CB, including dynamic state set via PSO -static void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_NODE *pPipe) { - for (uint32_t i = 0; i < pPipe->cbStateCI.attachmentCount; i++) { - if (0 != pPipe->pAttachments[i].colorWriteMask) { - pCB->status |= CBSTATUS_COLOR_BLEND_WRITE_ENABLE; - } - } - if (pPipe->dsStateCI.depthWriteEnable) { - pCB->status |= CBSTATUS_DEPTH_WRITE_ENABLE; - } - if (pPipe->dsStateCI.stencilTestEnable) { - pCB->status |= CBSTATUS_STENCIL_TEST_ENABLE; - } - // Account for any dynamic state not set via this PSO - if (!pPipe->dynStateCI.dynamicStateCount) { // All state is static - pCB->status = CBSTATUS_ALL; - } else { - // First consider all state on - // Then unset any state that's noted as dynamic in PSO - // Finally OR that into CB statemask - CBStatusFlags psoDynStateMask = CBSTATUS_ALL; - for (uint32_t i = 0; i < pPipe->dynStateCI.dynamicStateCount; i++) { - switch (pPipe->dynStateCI.pDynamicStates[i]) { - case VK_DYNAMIC_STATE_VIEWPORT: - psoDynStateMask &= ~CBSTATUS_VIEWPORT_SET; - break; - case VK_DYNAMIC_STATE_SCISSOR: - psoDynStateMask &= ~CBSTATUS_SCISSOR_SET; - break; - case VK_DYNAMIC_STATE_LINE_WIDTH: - psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET; - break; - case VK_DYNAMIC_STATE_DEPTH_BIAS: - psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET; - break; - case VK_DYNAMIC_STATE_BLEND_CONSTANTS: - psoDynStateMask &= ~CBSTATUS_BLEND_SET; - break; - case VK_DYNAMIC_STATE_DEPTH_BOUNDS: - psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET; - break; - case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK: - psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET; - break; - case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK: - psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET; - break; - case VK_DYNAMIC_STATE_STENCIL_REFERENCE: - psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET; - break; - default: - // TODO : Flag error here - break; - } - } - pCB->status |= psoDynStateMask; - } -} - -// Print the last bound Gfx Pipeline -static VkBool32 printPipeline(layer_data *my_data, const VkCommandBuffer cb) { - VkBool32 skipCall = VK_FALSE; - GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb); - if (pCB) { - PIPELINE_NODE *pPipeTrav = getPipeline(my_data, pCB->lastBoundPipeline); - if (!pPipeTrav) { - // nothing to print - } else { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_NONE, "DS", "%s", - vk_print_vkgraphicspipelinecreateinfo(&pPipeTrav->graphicsPipelineCI, "{DS}").c_str()); - } - } - return skipCall; -} - -// Print details of DS config to stdout -static VkBool32 printDSConfig(layer_data *my_data, const VkCommandBuffer cb) { - VkBool32 skipCall = VK_FALSE; - GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb); - if (pCB && pCB->lastBoundDescriptorSet) { - SET_NODE *pSet = getSetNode(my_data, pCB->lastBoundDescriptorSet); - DESCRIPTOR_POOL_NODE *pPool = getPoolNode(my_data, pSet->pool); - // Print out pool details - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_NONE, "DS", "Details for pool %#" PRIxLEAST64 ".", (uint64_t)pPool->pool); - string poolStr = vk_print_vkdescriptorpoolcreateinfo(&pPool->createInfo, " "); - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_NONE, "DS", "%s", poolStr.c_str()); - // Print out set details - char prefix[10]; - uint32_t index = 0; - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_NONE, "DS", "Details for descriptor set %#" PRIxLEAST64 ".", (uint64_t)pSet->set); - LAYOUT_NODE *pLayout = pSet->pLayout; - // Print layout details - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_NONE, "DS", "Layout #%u, (object %#" PRIxLEAST64 ") for DS %#" PRIxLEAST64 ".", index + 1, - (uint64_t)(pLayout->layout), (uint64_t)(pSet->set)); - sprintf(prefix, " [L%u] ", index); - string DSLstr = vk_print_vkdescriptorsetlayoutcreateinfo(&pLayout->createInfo, prefix).c_str(); - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_NONE, "DS", "%s", DSLstr.c_str()); - index++; - GENERIC_HEADER *pUpdate = pSet->pUpdateStructs; - if (pUpdate) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_NONE, "DS", "Update Chain [UC] for descriptor set %#" PRIxLEAST64 ":", (uint64_t)pSet->set); - sprintf(prefix, " [UC] "); - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_NONE, "DS", "%s", dynamic_display(pUpdate, prefix).c_str()); - // TODO : If there is a "view" associated with this update, print CI for that view - } else { - if (0 != pSet->descriptorCount) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_NONE, "DS", "No Update Chain for descriptor set %#" PRIxLEAST64 - " which has %u descriptors (vkUpdateDescriptors has not been called)", - (uint64_t)pSet->set, pSet->descriptorCount); - } else { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_NONE, "DS", "FYI: No descriptors in descriptor set %#" PRIxLEAST64 ".", (uint64_t)pSet->set); - } - } - } - return skipCall; -} - -static void printCB(layer_data *my_data, const VkCommandBuffer cb) { - GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb); - if (pCB && pCB->cmds.size() > 0) { - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_NONE, "DS", "Cmds in CB %p", (void *)cb); - vector<CMD_NODE> cmds = pCB->cmds; - for (auto ii = cmds.begin(); ii != cmds.end(); ++ii) { - // TODO : Need to pass cb as srcObj here - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, - __LINE__, DRAWSTATE_NONE, "DS", " CMD#%" PRIu64 ": %s", (*ii).cmdNumber, cmdTypeToString((*ii).type).c_str()); - } - } else { - // Nothing to print - } -} - -static VkBool32 synchAndPrintDSConfig(layer_data *my_data, const VkCommandBuffer cb) { - VkBool32 skipCall = VK_FALSE; - if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) { - return skipCall; - } - skipCall |= printDSConfig(my_data, cb); - skipCall |= printPipeline(my_data, cb); - return skipCall; -} - -// Flags validation error if the associated call is made inside a render pass. The apiName -// routine should ONLY be called outside a render pass. -static VkBool32 insideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) { - VkBool32 inside = VK_FALSE; - if (pCB->activeRenderPass) { - inside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS", - "%s: It is invalid to issue this call inside an active render pass (%#" PRIxLEAST64 ")", apiName, - (uint64_t)pCB->activeRenderPass); - } - return inside; -} - -// Flags validation error if the associated call is made outside a render pass. The apiName -// routine should ONLY be called inside a render pass. -static VkBool32 outsideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) { - VkBool32 outside = VK_FALSE; - if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) || - ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) && - !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) { - outside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS", - "%s: This call must be issued inside an active render pass.", apiName); - } - return outside; -} - -static void init_draw_state(layer_data *my_data, const VkAllocationCallbacks *pAllocator) { - uint32_t report_flags = 0; - uint32_t debug_action = 0; - FILE *log_output = NULL; - const char *option_str; - VkDebugReportCallbackEXT callback; - // initialize draw_state options - report_flags = getLayerOptionFlags("lunarg_draw_state.report_flags", 0); - getLayerOptionEnum("lunarg_draw_state.debug_action", (uint32_t *)&debug_action); - - if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG) { - option_str = getLayerOption("lunarg_draw_state.log_filename"); - log_output = getLayerLogOutput(option_str, "lunarg_draw_state"); - VkDebugReportCallbackCreateInfoEXT dbgInfo; - memset(&dbgInfo, 0, sizeof(dbgInfo)); - dbgInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; - dbgInfo.pfnCallback = log_callback; - dbgInfo.pUserData = log_output; - dbgInfo.flags = report_flags; - layer_create_msg_callback(my_data->report_data, &dbgInfo, pAllocator, &callback); - my_data->logging_callback.push_back(callback); - } - - if (debug_action & VK_DBG_LAYER_ACTION_DEBUG_OUTPUT) { - VkDebugReportCallbackCreateInfoEXT dbgInfo; - memset(&dbgInfo, 0, sizeof(dbgInfo)); - dbgInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; - dbgInfo.pfnCallback = win32_debug_output_msg; - dbgInfo.pUserData = log_output; - dbgInfo.flags = report_flags; - layer_create_msg_callback(my_data->report_data, &dbgInfo, pAllocator, &callback); - my_data->logging_callback.push_back(callback); - } - - if (!globalLockInitialized) { - loader_platform_thread_create_mutex(&globalLock); - globalLockInitialized = 1; - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) { - VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); - - assert(chain_info->u.pLayerInfo); - PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; - PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance"); - if (fpCreateInstance == NULL) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - // Advance the link info for the next element on the chain - chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; - - VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance); - if (result != VK_SUCCESS) - return result; - - // TBD: Need any locking this early, in case this function is called at the - // same time by more than one thread? - layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map); - my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable; - layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr); - - my_data->report_data = debug_report_create_instance(my_data->instance_dispatch_table, *pInstance, - pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames); - - init_draw_state(my_data, pAllocator); - - ValidateLayerOrdering(*pCreateInfo); - - return result; -} - -/* hook DestroyInstance to remove tableInstanceMap entry */ -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) { - // TODOSC : Shouldn't need any customization here - dispatch_key key = get_dispatch_key(instance); - // TBD: Need any locking this early, in case this function is called at the - // same time by more than one thread? - layer_data *my_data = get_my_data_ptr(key, layer_data_map); - VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; - pTable->DestroyInstance(instance, pAllocator); - - loader_platform_thread_lock_mutex(&globalLock); - - // Clean up logging callback, if any - while (my_data->logging_callback.size() > 0) { - VkDebugReportCallbackEXT callback = my_data->logging_callback.back(); - layer_destroy_msg_callback(my_data->report_data, callback, pAllocator); - my_data->logging_callback.pop_back(); - } - - layer_debug_report_destroy_instance(my_data->report_data); - delete my_data->instance_dispatch_table; - layer_data_map.erase(key); - // TODO : Potential race here with separate threads creating/destroying instance - if (layer_data_map.empty()) { - // Release mutex when destroying last instance. - loader_platform_thread_unlock_mutex(&globalLock); - loader_platform_thread_delete_mutex(&globalLock); - globalLockInitialized = 0; - } else { - loader_platform_thread_unlock_mutex(&globalLock); - } -} - -static void createDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) { - uint32_t i; - // TBD: Need any locking, in case this function is called at the same time - // by more than one thread? - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - dev_data->device_extensions.wsi_enabled = false; - - VkLayerDispatchTable *pDisp = dev_data->device_dispatch_table; - PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr; - - pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpa(device, "vkCreateSwapchainKHR"); - pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)gpa(device, "vkDestroySwapchainKHR"); - pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)gpa(device, "vkGetSwapchainImagesKHR"); - pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)gpa(device, "vkAcquireNextImageKHR"); - pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR)gpa(device, "vkQueuePresentKHR"); - - for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) { - if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) { - dev_data->device_extensions.wsi_enabled = true; - } - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) { - VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); - - assert(chain_info->u.pLayerInfo); - PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; - PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr; - PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice"); - if (fpCreateDevice == NULL) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - // Advance the link info for the next element on the chain - chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; - - VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice); - if (result != VK_SUCCESS) { - return result; - } - - loader_platform_thread_lock_mutex(&globalLock); - layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map); - layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map); - - // Setup device dispatch table - my_device_data->device_dispatch_table = new VkLayerDispatchTable; - layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr); - - my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice); - createDeviceRegisterExtensions(pCreateInfo, *pDevice); - // Get physical device limits for this device - my_instance_data->instance_dispatch_table->GetPhysicalDeviceProperties(gpu, &(my_device_data->physDevProperties.properties)); - uint32_t count; - my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr); - my_device_data->physDevProperties.queue_family_properties.resize(count); - my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties( - gpu, &count, &my_device_data->physDevProperties.queue_family_properties[0]); - // TODO: device limits should make sure these are compatible - if (pCreateInfo->pEnabledFeatures) { - my_device_data->physDevProperties.features = *pCreateInfo->pEnabledFeatures; - } else { - memset(&my_device_data->physDevProperties.features, 0, sizeof(VkPhysicalDeviceFeatures)); - } - loader_platform_thread_unlock_mutex(&globalLock); - - ValidateLayerOrdering(*pCreateInfo); - - return result; -} - -// prototype -static void deleteRenderPasses(layer_data *); -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) { - // TODOSC : Shouldn't need any customization here - dispatch_key key = get_dispatch_key(device); - layer_data *dev_data = get_my_data_ptr(key, layer_data_map); - // Free all the memory - loader_platform_thread_lock_mutex(&globalLock); - deletePipelines(dev_data); - deleteRenderPasses(dev_data); - deleteCommandBuffers(dev_data); - deletePools(dev_data); - deleteLayouts(dev_data); - dev_data->imageViewMap.clear(); - dev_data->imageMap.clear(); - dev_data->imageSubresourceMap.clear(); - dev_data->imageLayoutMap.clear(); - dev_data->memImageMap.clear(); - dev_data->bufferViewMap.clear(); - dev_data->bufferMap.clear(); - loader_platform_thread_unlock_mutex(&globalLock); - - dev_data->device_dispatch_table->DestroyDevice(device, pAllocator); - delete dev_data->device_dispatch_table; - layer_data_map.erase(key); -} - -static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}}; - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties) { - return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) { - return util_GetLayerProperties(ARRAY_SIZE(ds_global_layers), ds_global_layers, pCount, pProperties); -} - -// TODO: Why does this exist - can we just use global? -static const VkLayerProperties ds_device_layers[] = {{ - "VK_LAYER_LUNARG_draw_state", VK_API_VERSION, 1, "LunarG Validation Layer", -}}; - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, - const char *pLayerName, uint32_t *pCount, - VkExtensionProperties *pProperties) { - if (pLayerName == NULL) { - dispatch_key key = get_dispatch_key(physicalDevice); - layer_data *my_data = get_my_data_ptr(key, layer_data_map); - return my_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties); - } else { - return util_GetExtensionProperties(0, NULL, pCount, pProperties); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties) { - /* draw_state physical device layers are the same as global */ - return util_GetLayerProperties(ARRAY_SIZE(ds_device_layers), ds_device_layers, pCount, pProperties); -} - -// This validates that the initial layout specified in the command buffer for -// the IMAGE is the same -// as the global IMAGE layout -VkBool32 ValidateCmdBufImageLayouts(VkCommandBuffer cmdBuffer) { - VkBool32 skip_call = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); - for (auto cb_image_data : pCB->imageLayoutMap) { - VkImageLayout imageLayout; - if (!FindLayout(dev_data, cb_image_data.first, imageLayout)) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, - __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot submit cmd buffer using deleted image %" PRIu64 ".", - reinterpret_cast<const uint64_t &>(cb_image_data.first)); - } else { - if (cb_image_data.second.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) { - // TODO: Set memory invalid which is in mem_tracker currently - } else if (imageLayout != cb_image_data.second.initialLayout) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, - "DS", "Cannot submit cmd buffer using image with layout %s when " - "first use is %s.", - string_VkImageLayout(imageLayout), string_VkImageLayout(cb_image_data.second.initialLayout)); - } - SetLayout(dev_data, cb_image_data.first, cb_image_data.second.layout); - } - } - return skip_call; -} -// Track which resources are in-flight by atomically incrementing their "in_use" count -VkBool32 validateAndIncrementResources(layer_data *my_data, GLOBAL_CB_NODE *pCB) { - VkBool32 skip_call = VK_FALSE; - for (auto drawDataElement : pCB->drawData) { - for (auto buffer : drawDataElement.buffers) { - auto buffer_data = my_data->bufferMap.find(buffer); - if (buffer_data == my_data->bufferMap.end()) { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, - (uint64_t)(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS", - "Cannot submit cmd buffer using deleted buffer %" PRIu64 ".", (uint64_t)(buffer)); - } else { - buffer_data->second.in_use.fetch_add(1); - } - } - } - for (auto set : pCB->uniqueBoundSets) { - auto setNode = my_data->setMap.find(set); - if (setNode == my_data->setMap.end()) { - skip_call |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - (uint64_t)(set), __LINE__, DRAWSTATE_INVALID_DESCRIPTOR_SET, "DS", - "Cannot submit cmd buffer using deleted descriptor set %" PRIu64 ".", (uint64_t)(set)); - } else { - setNode->second->in_use.fetch_add(1); - } - } - for (auto semaphore : pCB->semaphores) { - auto semaphoreNode = my_data->semaphoreMap.find(semaphore); - if (semaphoreNode == my_data->semaphoreMap.end()) { - skip_call |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS", - "Cannot submit cmd buffer using deleted semaphore %" PRIu64 ".", reinterpret_cast<uint64_t &>(semaphore)); - } else { - semaphoreNode->second.in_use.fetch_add(1); - } - } - for (auto event : pCB->events) { - auto eventNode = my_data->eventMap.find(event); - if (eventNode == my_data->eventMap.end()) { - skip_call |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS", - "Cannot submit cmd buffer using deleted event %" PRIu64 ".", reinterpret_cast<uint64_t &>(event)); - } else { - eventNode->second.in_use.fetch_add(1); - } - } - return skip_call; -} - -void decrementResources(layer_data *my_data, VkCommandBuffer cmdBuffer) { - GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer); - for (auto drawDataElement : pCB->drawData) { - for (auto buffer : drawDataElement.buffers) { - auto buffer_data = my_data->bufferMap.find(buffer); - if (buffer_data != my_data->bufferMap.end()) { - buffer_data->second.in_use.fetch_sub(1); - } - } - } - for (auto set : pCB->uniqueBoundSets) { - auto setNode = my_data->setMap.find(set); - if (setNode != my_data->setMap.end()) { - setNode->second->in_use.fetch_sub(1); - } - } - for (auto semaphore : pCB->semaphores) { - auto semaphoreNode = my_data->semaphoreMap.find(semaphore); - if (semaphoreNode != my_data->semaphoreMap.end()) { - semaphoreNode->second.in_use.fetch_sub(1); - } - } - for (auto event : pCB->events) { - auto eventNode = my_data->eventMap.find(event); - if (eventNode != my_data->eventMap.end()) { - eventNode->second.in_use.fetch_sub(1); - } - } - for (auto queryStatePair : pCB->queryToStateMap) { - my_data->queryToStateMap[queryStatePair.first] = queryStatePair.second; - } - for (auto eventStagePair : pCB->eventToStageMap) { - my_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second; - } -} - -void decrementResources(layer_data *my_data, uint32_t fenceCount, const VkFence *pFences) { - for (uint32_t i = 0; i < fenceCount; ++i) { - auto fence_data = my_data->fenceMap.find(pFences[i]); - if (fence_data == my_data->fenceMap.end() || !fence_data->second.needsSignaled) - return; - fence_data->second.needsSignaled = false; - fence_data->second.in_use.fetch_sub(1); - if (fence_data->second.priorFence != VK_NULL_HANDLE) { - decrementResources(my_data, 1, &fence_data->second.priorFence); - } - for (auto cmdBuffer : fence_data->second.cmdBuffers) { - decrementResources(my_data, cmdBuffer); - } - } -} - -void decrementResources(layer_data *my_data, VkQueue queue) { - auto queue_data = my_data->queueMap.find(queue); - if (queue_data != my_data->queueMap.end()) { - for (auto cmdBuffer : queue_data->second.untrackedCmdBuffers) { - decrementResources(my_data, cmdBuffer); - } - queue_data->second.untrackedCmdBuffers.clear(); - decrementResources(my_data, 1, &queue_data->second.priorFence); - } -} - -void trackCommandBuffers(layer_data *my_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) { - auto queue_data = my_data->queueMap.find(queue); - if (fence != VK_NULL_HANDLE) { - VkFence priorFence = VK_NULL_HANDLE; - auto fence_data = my_data->fenceMap.find(fence); - if (fence_data == my_data->fenceMap.end()) { - return; - } - if (queue_data != my_data->queueMap.end()) { - priorFence = queue_data->second.priorFence; - queue_data->second.priorFence = fence; - for (auto cmdBuffer : queue_data->second.untrackedCmdBuffers) { - fence_data->second.cmdBuffers.push_back(cmdBuffer); - } - queue_data->second.untrackedCmdBuffers.clear(); - } - fence_data->second.cmdBuffers.clear(); - fence_data->second.priorFence = priorFence; - fence_data->second.needsSignaled = true; - fence_data->second.queue = queue; - fence_data->second.in_use.fetch_add(1); - for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { - const VkSubmitInfo *submit = &pSubmits[submit_idx]; - for (uint32_t i = 0; i < submit->commandBufferCount; ++i) { - for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) { - fence_data->second.cmdBuffers.push_back(secondaryCmdBuffer); - } - fence_data->second.cmdBuffers.push_back(submit->pCommandBuffers[i]); - } - } - } else { - if (queue_data != my_data->queueMap.end()) { - for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { - const VkSubmitInfo *submit = &pSubmits[submit_idx]; - for (uint32_t i = 0; i < submit->commandBufferCount; ++i) { - for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) { - queue_data->second.untrackedCmdBuffers.push_back(secondaryCmdBuffer); - } - queue_data->second.untrackedCmdBuffers.push_back(submit->pCommandBuffers[i]); - } - } - } - } - if (queue_data != my_data->queueMap.end()) { - for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { - const VkSubmitInfo *submit = &pSubmits[submit_idx]; - for (uint32_t i = 0; i < submit->commandBufferCount; ++i) { - // Add cmdBuffers to both the global set and queue set - for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) { - my_data->globalInFlightCmdBuffers.insert(secondaryCmdBuffer); - queue_data->second.inFlightCmdBuffers.insert(secondaryCmdBuffer); - } - my_data->globalInFlightCmdBuffers.insert(submit->pCommandBuffers[i]); - queue_data->second.inFlightCmdBuffers.insert(submit->pCommandBuffers[i]); - } - } - } -} - -bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB) { - bool skip_call = false; - if (dev_data->globalInFlightCmdBuffers.count(pCB->commandBuffer) && - !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, - __LINE__, DRAWSTATE_INVALID_FENCE, "DS", "Command Buffer %#" PRIx64 " is already in use and is not marked " - "for simultaneous use.", - reinterpret_cast<uint64_t>(pCB->commandBuffer)); - } - return skip_call; -} - -static bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) { - bool skipCall = false; - // Validate that cmd buffers have been updated - if (CB_RECORDED != pCB->state) { - if (CB_INVALID == pCB->state) { - // Inform app of reason CB invalid - bool causeReported = false; - if (!pCB->destroyedSets.empty()) { - std::stringstream set_string; - for (auto set : pCB->destroyedSets) - set_string << " " << set; - - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", - "You are submitting command buffer %#" PRIxLEAST64 - " that is invalid because it had the following bound descriptor set(s) destroyed: %s", - (uint64_t)(pCB->commandBuffer), set_string.str().c_str()); - causeReported = true; - } - if (!pCB->updatedSets.empty()) { - std::stringstream set_string; - for (auto set : pCB->updatedSets) - set_string << " " << set; - - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", - "You are submitting command buffer %#" PRIxLEAST64 - " that is invalid because it had the following bound descriptor set(s) updated: %s", - (uint64_t)(pCB->commandBuffer), set_string.str().c_str()); - causeReported = true; - } - if (!pCB->destroyedFramebuffers.empty()) { - std::stringstream fb_string; - for (auto fb : pCB->destroyedFramebuffers) - fb_string << " " << fb; - - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", - "You are submitting command buffer %#" PRIxLEAST64 " that is invalid because it had the following " - "referenced framebuffers destroyed: %s", - reinterpret_cast<uint64_t &>(pCB->commandBuffer), fb_string.str().c_str()); - causeReported = true; - } - // TODO : This is defensive programming to make sure an error is - // flagged if we hit this INVALID cmd buffer case and none of the - // above cases are hit. As the number of INVALID cases grows, this - // code should be updated to seemlessly handle all the cases. - if (!causeReported) { - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", - "You are submitting command buffer %#" PRIxLEAST64 " that is invalid due to an unknown cause. Validation " - "should " - "be improved to report the exact cause.", - reinterpret_cast<uint64_t &>(pCB->commandBuffer)); - } - } else { // Flag error for using CB w/o vkEndCommandBuffer() called - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS", - "You must call vkEndCommandBuffer() on CB %#" PRIxLEAST64 " before this call to vkQueueSubmit()!", - (uint64_t)(pCB->commandBuffer)); - } - } - return skipCall; -} - -static VkBool32 validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) { - // Track in-use for resources off of primary and any secondary CBs - VkBool32 skipCall = validateAndIncrementResources(dev_data, pCB); - if (!pCB->secondaryCommandBuffers.empty()) { - for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) { - skipCall |= validateAndIncrementResources(dev_data, dev_data->commandBufferMap[secondaryCmdBuffer]); - GLOBAL_CB_NODE *pSubCB = getCBNode(dev_data, secondaryCmdBuffer); - if (pSubCB->primaryCommandBuffer != pCB->commandBuffer) { - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, - __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS", - "CB %#" PRIxLEAST64 " was submitted with secondary buffer %#" PRIxLEAST64 - " but that buffer has subsequently been bound to " - "primary cmd buffer %#" PRIxLEAST64 ".", - reinterpret_cast<uint64_t>(pCB->commandBuffer), reinterpret_cast<uint64_t>(secondaryCmdBuffer), - reinterpret_cast<uint64_t>(pSubCB->primaryCommandBuffer)); - } - } - } - // TODO : Verify if this also needs to be checked for secondary command - // buffers. If so, this block of code can move to - // validateCommandBufferState() function. vulkan GL106 filed to clarify - if ((pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) && (pCB->submitCount > 1)) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, - __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS", - "CB %#" PRIxLEAST64 " was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT " - "set, but has been submitted %#" PRIxLEAST64 " times.", - (uint64_t)(pCB->commandBuffer), pCB->submitCount); - } - skipCall |= validateCommandBufferState(dev_data, pCB); - // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing - // on device - skipCall |= validateCommandBufferSimultaneousUse(dev_data, pCB); - return skipCall; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) { - VkBool32 skipCall = VK_FALSE; - GLOBAL_CB_NODE *pCB = NULL; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - // First verify that fence is not in use - if ((fence != VK_NULL_HANDLE) && (submitCount != 0) && dev_data->fenceMap[fence].in_use.load()) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, - (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", - "Fence %#" PRIx64 " is already in use by another submission.", (uint64_t)(fence)); - } - // Now verify each individual submit - for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { - const VkSubmitInfo *submit = &pSubmits[submit_idx]; - vector<VkSemaphore> semaphoreList; - for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) { - semaphoreList.push_back(submit->pWaitSemaphores[i]); - if (dev_data->semaphoreMap[submit->pWaitSemaphores[i]].signaled) { - dev_data->semaphoreMap[submit->pWaitSemaphores[i]].signaled = 0; - } else { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, - "DS", "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.", - (uint64_t)(queue), (uint64_t)(submit->pWaitSemaphores[i])); - } - } - for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) { - semaphoreList.push_back(submit->pSignalSemaphores[i]); - dev_data->semaphoreMap[submit->pSignalSemaphores[i]].signaled = 1; - } - for (uint32_t i = 0; i < submit->commandBufferCount; i++) { - skipCall |= ValidateCmdBufImageLayouts(submit->pCommandBuffers[i]); - pCB = getCBNode(dev_data, submit->pCommandBuffers[i]); - pCB->semaphores = semaphoreList; - pCB->submitCount++; // increment submit count - skipCall |= validatePrimaryCommandBufferState(dev_data, pCB); - } - } - // Update cmdBuffer-related data structs and mark fence in-use - trackCommandBuffers(dev_data, queue, submitCount, pSubmits, fence); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - return dev_data->device_dispatch_table->QueueSubmit(queue, submitCount, pSubmits, fence); - return VK_ERROR_VALIDATION_FAILED_EXT; -} - -// Note: This function assumes that the global lock is held by the calling -// thread. -VkBool32 cleanInFlightCmdBuffer(layer_data *my_data, VkCommandBuffer cmdBuffer) { - VkBool32 skip_call = VK_FALSE; - GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer); - if (pCB) { - for (auto queryEventsPair : pCB->waitedEventsBeforeQueryReset) { - for (auto event : queryEventsPair.second) { - if (my_data->eventMap[event].needsSignaled) { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS", - "Cannot get query results on queryPool %" PRIu64 - " with index %d which was guarded by unsignaled event %" PRIu64 ".", - (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event)); - } - } - } - } - return skip_call; -} -// Remove given cmd_buffer from the global inFlight set. -// Also, if given queue is valid, then remove the cmd_buffer from that queues -// inFlightCmdBuffer set. Finally, check all other queues and if given cmd_buffer -// is still in flight on another queue, add it back into the global set. -// Note: This function assumes that the global lock is held by the calling -// thread. -static inline void removeInFlightCmdBuffer(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkQueue queue) { - // Pull it off of global list initially, but if we find it in any other queue list, add it back in - dev_data->globalInFlightCmdBuffers.erase(cmd_buffer); - if (dev_data->queueMap.find(queue) != dev_data->queueMap.end()) { - dev_data->queueMap[queue].inFlightCmdBuffers.erase(cmd_buffer); - for (auto q : dev_data->queues) { - if ((q != queue) && - (dev_data->queueMap[q].inFlightCmdBuffers.find(cmd_buffer) != dev_data->queueMap[q].inFlightCmdBuffers.end())) { - dev_data->globalInFlightCmdBuffers.insert(cmd_buffer); - break; - } - } - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->WaitForFences(device, fenceCount, pFences, waitAll, timeout); - VkBool32 skip_call = VK_FALSE; - loader_platform_thread_lock_mutex(&globalLock); - if (result == VK_SUCCESS) { - // When we know that all fences are complete we can clean/remove their CBs - if (waitAll || fenceCount == 1) { - for (uint32_t i = 0; i < fenceCount; ++i) { - VkQueue fence_queue = dev_data->fenceMap[pFences[i]].queue; - for (auto cmdBuffer : dev_data->fenceMap[pFences[i]].cmdBuffers) { - skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); - removeInFlightCmdBuffer(dev_data, cmdBuffer, fence_queue); - } - } - decrementResources(dev_data, fenceCount, pFences); - } - // NOTE : Alternate case not handled here is when some fences have completed. In - // this case for app to guarantee which fences completed it will have to call - // vkGetFenceStatus() at which point we'll clean/remove their CBs if complete. - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE != skip_call) - return VK_ERROR_VALIDATION_FAILED_EXT; - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus(VkDevice device, VkFence fence) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->GetFenceStatus(device, fence); - VkBool32 skip_call = VK_FALSE; - loader_platform_thread_lock_mutex(&globalLock); - if (result == VK_SUCCESS) { - auto fence_queue = dev_data->fenceMap[fence].queue; - for (auto cmdBuffer : dev_data->fenceMap[fence].cmdBuffers) { - skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); - removeInFlightCmdBuffer(dev_data, cmdBuffer, fence_queue); - } - decrementResources(dev_data, 1, &fence); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE != skip_call) - return VK_ERROR_VALIDATION_FAILED_EXT; - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - dev_data->device_dispatch_table->GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue); - dev_data->queues.push_back(*pQueue); - dev_data->queueMap[*pQueue].device = device; - loader_platform_thread_unlock_mutex(&globalLock); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle(VkQueue queue) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); - decrementResources(dev_data, queue); - VkBool32 skip_call = VK_FALSE; - loader_platform_thread_lock_mutex(&globalLock); - // Iterate over local set since we erase set members as we go in for loop - auto local_cb_set = dev_data->queueMap[queue].inFlightCmdBuffers; - for (auto cmdBuffer : local_cb_set) { - skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); - removeInFlightCmdBuffer(dev_data, cmdBuffer, queue); - } - dev_data->queueMap[queue].inFlightCmdBuffers.clear(); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE != skip_call) - return VK_ERROR_VALIDATION_FAILED_EXT; - return dev_data->device_dispatch_table->QueueWaitIdle(queue); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle(VkDevice device) { - VkBool32 skip_call = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - for (auto queue : dev_data->queues) { - decrementResources(dev_data, queue); - if (dev_data->queueMap.find(queue) != dev_data->queueMap.end()) { - // Clear all of the queue inFlightCmdBuffers (global set cleared below) - dev_data->queueMap[queue].inFlightCmdBuffers.clear(); - } - } - for (auto cmdBuffer : dev_data->globalInFlightCmdBuffers) { - skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer); - } - dev_data->globalInFlightCmdBuffers.clear(); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE != skip_call) - return VK_ERROR_VALIDATION_FAILED_EXT; - return dev_data->device_dispatch_table->DeviceWaitIdle(device); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - bool skipCall = false; - loader_platform_thread_lock_mutex(&globalLock); - if (dev_data->fenceMap[fence].in_use.load()) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, - (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", - "Fence %#" PRIx64 " is in use by a command buffer.", (uint64_t)(fence)); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (!skipCall) - dev_data->device_dispatch_table->DestroyFence(device, fence, pAllocator); - // TODO : Clean up any internal data structures using this obj. -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - dev_data->device_dispatch_table->DestroySemaphore(device, semaphore, pAllocator); - loader_platform_thread_lock_mutex(&globalLock); - if (dev_data->semaphoreMap[semaphore].in_use.load()) { - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, - reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS", - "Cannot delete semaphore %" PRIx64 " which is in use.", reinterpret_cast<uint64_t &>(semaphore)); - } - dev_data->semaphoreMap.erase(semaphore); - loader_platform_thread_unlock_mutex(&globalLock); - // TODO : Clean up any internal data structures using this obj. -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - bool skip_call = false; - loader_platform_thread_lock_mutex(&globalLock); - auto event_data = dev_data->eventMap.find(event); - if (event_data != dev_data->eventMap.end()) { - if (event_data->second.in_use.load()) { - skip_call |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS", - "Cannot delete event %" PRIx64 " which is in use by a command buffer.", reinterpret_cast<uint64_t &>(event)); - } - dev_data->eventMap.erase(event_data); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (!skip_call) - dev_data->device_dispatch_table->DestroyEvent(device, event, pAllocator); - // TODO : Clean up any internal data structures using this obj. -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) { - get_my_data_ptr(get_dispatch_key(device), layer_data_map) - ->device_dispatch_table->DestroyQueryPool(device, queryPool, pAllocator); - // TODO : Clean up any internal data structures using this obj. -} - -VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, - uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride, - VkQueryResultFlags flags) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - unordered_map<QueryObject, vector<VkCommandBuffer>> queriesInFlight; - GLOBAL_CB_NODE *pCB = nullptr; - loader_platform_thread_lock_mutex(&globalLock); - for (auto cmdBuffer : dev_data->globalInFlightCmdBuffers) { - pCB = getCBNode(dev_data, cmdBuffer); - for (auto queryStatePair : pCB->queryToStateMap) { - queriesInFlight[queryStatePair.first].push_back(cmdBuffer); - } - } - VkBool32 skip_call = VK_FALSE; - for (uint32_t i = 0; i < queryCount; ++i) { - QueryObject query = {queryPool, firstQuery + i}; - auto queryElement = queriesInFlight.find(query); - auto queryToStateElement = dev_data->queryToStateMap.find(query); - if (queryToStateElement != dev_data->queryToStateMap.end()) { - } - // Available and in flight - if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() && - queryToStateElement->second) { - for (auto cmdBuffer : queryElement->second) { - pCB = getCBNode(dev_data, cmdBuffer); - auto queryEventElement = pCB->waitedEventsBeforeQueryReset.find(query); - if (queryEventElement == pCB->waitedEventsBeforeQueryReset.end()) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", - "Cannot get query results on queryPool %" PRIu64 " with index %d which is in flight.", - (uint64_t)(queryPool), firstQuery + i); - } else { - for (auto event : queryEventElement->second) { - dev_data->eventMap[event].needsSignaled = true; - } - } - } - // Unavailable and in flight - } else if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() && - !queryToStateElement->second) { - // TODO : Can there be the same query in use by multiple command buffers in flight? - bool make_available = false; - for (auto cmdBuffer : queryElement->second) { - pCB = getCBNode(dev_data, cmdBuffer); - make_available |= pCB->queryToStateMap[query]; - } - if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", - "Cannot get query results on queryPool %" PRIu64 " with index %d which is unavailable.", - (uint64_t)(queryPool), firstQuery + i); - } - // Unavailable - } else if (queryToStateElement != dev_data->queryToStateMap.end() && !queryToStateElement->second) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, - 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", - "Cannot get query results on queryPool %" PRIu64 " with index %d which is unavailable.", - (uint64_t)(queryPool), firstQuery + i); - // Unitialized - } else if (queryToStateElement == dev_data->queryToStateMap.end()) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, - 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS", - "Cannot get query results on queryPool %" PRIu64 " with index %d which is uninitialized.", - (uint64_t)(queryPool), firstQuery + i); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - if (skip_call) - return VK_ERROR_VALIDATION_FAILED_EXT; - return dev_data->device_dispatch_table->GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, - flags); -} - -VkBool32 validateIdleBuffer(const layer_data *my_data, VkBuffer buffer) { - VkBool32 skip_call = VK_FALSE; - auto buffer_data = my_data->bufferMap.find(buffer); - if (buffer_data == my_data->bufferMap.end()) { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, - (uint64_t)(buffer), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS", - "Cannot free buffer %" PRIxLEAST64 " that has not been allocated.", (uint64_t)(buffer)); - } else { - if (buffer_data->second.in_use.load()) { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, - (uint64_t)(buffer), __LINE__, DRAWSTATE_OBJECT_INUSE, "DS", - "Cannot free buffer %" PRIxLEAST64 " that is in use by a command buffer.", (uint64_t)(buffer)); - } - } - return skip_call; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - if (!validateIdleBuffer(dev_data, buffer)) { - loader_platform_thread_unlock_mutex(&globalLock); - dev_data->device_dispatch_table->DestroyBuffer(device, buffer, pAllocator); - loader_platform_thread_lock_mutex(&globalLock); - } - dev_data->bufferMap.erase(buffer); - loader_platform_thread_unlock_mutex(&globalLock); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - dev_data->device_dispatch_table->DestroyBufferView(device, bufferView, pAllocator); - loader_platform_thread_lock_mutex(&globalLock); - dev_data->bufferViewMap.erase(bufferView); - loader_platform_thread_unlock_mutex(&globalLock); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - dev_data->device_dispatch_table->DestroyImage(device, image, pAllocator); - loader_platform_thread_lock_mutex(&globalLock); - const auto& entry = dev_data->imageMap.find(image); - if (entry != dev_data->imageMap.end()) { - dev_data->memImageMap.erase(entry->second.mem); - dev_data->imageMap.erase(entry); - } - const auto& subEntry = dev_data->imageSubresourceMap.find(image); - if (subEntry != dev_data->imageSubresourceMap.end()) { - for (const auto& pair : subEntry->second) { - dev_data->imageLayoutMap.erase(pair); - } - dev_data->imageSubresourceMap.erase(subEntry); - } - loader_platform_thread_unlock_mutex(&globalLock); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) { - get_my_data_ptr(get_dispatch_key(device), layer_data_map) - ->device_dispatch_table->DestroyImageView(device, imageView, pAllocator); - // TODO : Clean up any internal data structures using this obj. -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator) { - get_my_data_ptr(get_dispatch_key(device), layer_data_map) - ->device_dispatch_table->DestroyShaderModule(device, shaderModule, pAllocator); - // TODO : Clean up any internal data structures using this obj. -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) { - get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroyPipeline(device, pipeline, pAllocator); - // TODO : Clean up any internal data structures using this obj. -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator) { - get_my_data_ptr(get_dispatch_key(device), layer_data_map) - ->device_dispatch_table->DestroyPipelineLayout(device, pipelineLayout, pAllocator); - // TODO : Clean up any internal data structures using this obj. -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) { - get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroySampler(device, sampler, pAllocator); - // TODO : Clean up any internal data structures using this obj. -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator) { - get_my_data_ptr(get_dispatch_key(device), layer_data_map) - ->device_dispatch_table->DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator); - // TODO : Clean up any internal data structures using this obj. -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) { - get_my_data_ptr(get_dispatch_key(device), layer_data_map) - ->device_dispatch_table->DestroyDescriptorPool(device, descriptorPool, pAllocator); - // TODO : Clean up any internal data structures using this obj. -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t count, const VkCommandBuffer *pCommandBuffers) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - - bool skip_call = false; - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < count; i++) { - if (dev_data->globalInFlightCmdBuffers.count(pCommandBuffers[i])) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", - "Attempt to free command buffer (%#" PRIxLEAST64 ") which is in use.", - reinterpret_cast<uint64_t>(pCommandBuffers[i])); - } - // Delete CB information structure, and remove from commandBufferMap - auto cb = dev_data->commandBufferMap.find(pCommandBuffers[i]); - if (cb != dev_data->commandBufferMap.end()) { - // reset prior to delete for data clean-up - resetCB(dev_data, (*cb).second->commandBuffer); - delete (*cb).second; - dev_data->commandBufferMap.erase(cb); - } - - // Remove commandBuffer reference from commandPoolMap - dev_data->commandPoolMap[commandPool].commandBuffers.remove(pCommandBuffers[i]); - } - loader_platform_thread_unlock_mutex(&globalLock); - - if (!skip_call) - dev_data->device_dispatch_table->FreeCommandBuffers(device, commandPool, count, pCommandBuffers); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkCommandPool *pCommandPool) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - - VkResult result = dev_data->device_dispatch_table->CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool); - - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags; - dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex; - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) { - - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool); - if (result == VK_SUCCESS) { - loader_platform_thread_lock_mutex(&globalLock); - dev_data->queryPoolMap[*pQueryPool].createInfo = *pCreateInfo; - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VkBool32 validateCommandBuffersNotInUse(const layer_data *dev_data, VkCommandPool commandPool) { - VkBool32 skipCall = VK_FALSE; - auto pool_data = dev_data->commandPoolMap.find(commandPool); - if (pool_data != dev_data->commandPoolMap.end()) { - for (auto cmdBuffer : pool_data->second.commandBuffers) { - if (dev_data->globalInFlightCmdBuffers.count(cmdBuffer)) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT, - (uint64_t)(commandPool), __LINE__, DRAWSTATE_OBJECT_INUSE, "DS", - "Cannot reset command pool %" PRIx64 " when allocated command buffer %" PRIx64 " is in use.", - (uint64_t)(commandPool), (uint64_t)(cmdBuffer)); - } - } - } - return skipCall; -} - -// Destroy commandPool along with all of the commandBuffers allocated from that pool -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - - // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandPoolMap - if (dev_data->commandPoolMap.find(commandPool) != dev_data->commandPoolMap.end()) { - for (auto poolCb = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); - poolCb != dev_data->commandPoolMap[commandPool].commandBuffers.end();) { - auto del_cb = dev_data->commandBufferMap.find(*poolCb); - delete (*del_cb).second; // delete CB info structure - dev_data->commandBufferMap.erase(del_cb); // Remove this command buffer from cbMap - poolCb = dev_data->commandPoolMap[commandPool].commandBuffers.erase( - poolCb); // Remove CB reference from commandPoolMap's list - } - } - dev_data->commandPoolMap.erase(commandPool); - - loader_platform_thread_unlock_mutex(&globalLock); - - if (VK_TRUE == validateCommandBuffersNotInUse(dev_data, commandPool)) - return; - - dev_data->device_dispatch_table->DestroyCommandPool(device, commandPool, pAllocator); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - - if (VK_TRUE == validateCommandBuffersNotInUse(dev_data, commandPool)) - return VK_ERROR_VALIDATION_FAILED_EXT; - - result = dev_data->device_dispatch_table->ResetCommandPool(device, commandPool, flags); - // Reset all of the CBs allocated from this pool - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin(); - while (it != dev_data->commandPoolMap[commandPool].commandBuffers.end()) { - resetCB(dev_data, (*it)); - ++it; - } - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - bool skipCall = false; - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < fenceCount; ++i) { - if (dev_data->fenceMap[pFences[i]].in_use.load()) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, - reinterpret_cast<const uint64_t &>(pFences[i]), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", - "Fence %#" PRIx64 " is in use by a command buffer.", reinterpret_cast<const uint64_t &>(pFences[i])); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - if (!skipCall) - result = dev_data->device_dispatch_table->ResetFences(device, fenceCount, pFences); - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - auto fbNode = dev_data->frameBufferMap.find(framebuffer); - if (fbNode != dev_data->frameBufferMap.end()) { - for (auto cb : fbNode->second.referencingCmdBuffers) { - auto cbNode = dev_data->commandBufferMap.find(cb); - if (cbNode != dev_data->commandBufferMap.end()) { - // Set CB as invalid and record destroyed framebuffer - cbNode->second->state = CB_INVALID; - cbNode->second->destroyedFramebuffers.insert(framebuffer); - } - } - dev_data->frameBufferMap.erase(framebuffer); - } - dev_data->device_dispatch_table->DestroyFramebuffer(device, framebuffer, pAllocator); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) { - get_my_data_ptr(get_dispatch_key(device), layer_data_map) - ->device_dispatch_table->DestroyRenderPass(device, renderPass, pAllocator); - // TODO : Clean up any internal data structures using this obj. -} - -VkBool32 validate_queue_family_indices(layer_data *dev_data, const char *function_name, const uint32_t count, - const uint32_t *indices) { - VkBool32 skipCall = VK_FALSE; - for (auto i = 0; i < count; i++) { - if (indices[i] >= dev_data->physDevProperties.queue_family_properties.size()) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_QUEUE_INDEX, "DS", - "%s has QueueFamilyIndex greater than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER - ") for this device.", - function_name, dev_data->physDevProperties.queue_family_properties.size()); - } - } - return skipCall; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) { - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - bool skipCall = validate_queue_family_indices(dev_data, "vkCreateBuffer", pCreateInfo->queueFamilyIndexCount, - pCreateInfo->pQueueFamilyIndices); - if (!skipCall) { - result = dev_data->device_dispatch_table->CreateBuffer(device, pCreateInfo, pAllocator, pBuffer); - } - - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - // TODO : This doesn't create deep copy of pQueueFamilyIndices so need to fix that if/when we want that data to be valid - dev_data->bufferMap[*pBuffer].create_info = unique_ptr<VkBufferCreateInfo>(new VkBufferCreateInfo(*pCreateInfo)); - dev_data->bufferMap[*pBuffer].in_use.store(0); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkBufferView *pView) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreateBufferView(device, pCreateInfo, pAllocator, pView); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - dev_data->bufferViewMap[*pView] = unique_ptr<VkBufferViewCreateInfo>(new VkBufferViewCreateInfo(*pCreateInfo)); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage) { - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - bool skipCall = validate_queue_family_indices(dev_data, "vkCreateImage", pCreateInfo->queueFamilyIndexCount, - pCreateInfo->pQueueFamilyIndices); - if (!skipCall) { - result = dev_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage); - } - - if (VK_SUCCESS == result) { - IMAGE_LAYOUT_NODE image_node; - image_node.layout = pCreateInfo->initialLayout; - image_node.format = pCreateInfo->format; - loader_platform_thread_lock_mutex(&globalLock); - dev_data->imageMap[*pImage].createInfo = *pCreateInfo; - ImageSubresourcePair subpair = {*pImage, false, VkImageSubresource()}; - dev_data->imageSubresourceMap[*pImage].push_back(subpair); - dev_data->imageLayoutMap[subpair] = image_node; - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -static void ResolveRemainingLevelsLayers(layer_data *dev_data, VkImageSubresourceRange *range, VkImage image) { - /* expects globalLock to be held by caller */ - - auto image_node_it = dev_data->imageMap.find(image); - if (image_node_it != dev_data->imageMap.end()) { - /* If the caller used the special values VK_REMAINING_MIP_LEVELS and - * VK_REMAINING_ARRAY_LAYERS, resolve them now in our internal state to - * the actual values. - */ - if (range->levelCount == VK_REMAINING_MIP_LEVELS) { - range->levelCount = image_node_it->second.createInfo.mipLevels - range->baseMipLevel; - } - - if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) { - range->layerCount = image_node_it->second.createInfo.arrayLayers - range->baseArrayLayer; - } - } -} - -// Return the correct layer/level counts if the caller used the special -// values VK_REMAINING_MIP_LEVELS or VK_REMAINING_ARRAY_LAYERS. -static void ResolveRemainingLevelsLayers(layer_data *dev_data, uint32_t *levels, uint32_t *layers, VkImageSubresourceRange range, - VkImage image) { - /* expects globalLock to be held by caller */ - - *levels = range.levelCount; - *layers = range.layerCount; - auto image_node_it = dev_data->imageMap.find(image); - if (image_node_it != dev_data->imageMap.end()) { - if (range.levelCount == VK_REMAINING_MIP_LEVELS) { - *levels = image_node_it->second.createInfo.mipLevels - range.baseMipLevel; - } - if (range.layerCount == VK_REMAINING_ARRAY_LAYERS) { - *layers = image_node_it->second.createInfo.arrayLayers - range.baseArrayLayer; - } - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkImageView *pView) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreateImageView(device, pCreateInfo, pAllocator, pView); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - auto image_view = unique_ptr<VkImageViewCreateInfo>(new VkImageViewCreateInfo(*pCreateInfo)); - ResolveRemainingLevelsLayers(dev_data, &image_view->subresourceRange, pCreateInfo->image); - dev_data->imageViewMap[*pView] = std::move(image_view); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreateFence(device, pCreateInfo, pAllocator, pFence); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - dev_data->fenceMap[*pFence].in_use.store(0); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -// TODO handle pipeline caches -VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache); - return result; -} - -VKAPI_ATTR void VKAPI_CALL -vkDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks *pAllocator) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - dev_data->device_dispatch_table->DestroyPipelineCache(device, pipelineCache, pAllocator); -} - -VKAPI_ATTR VkResult VKAPI_CALL -vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize, void *pData) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->GetPipelineCacheData(device, pipelineCache, pDataSize, pData); - return result; -} - -VKAPI_ATTR VkResult VKAPI_CALL -vkMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches); - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count, - const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, - VkPipeline *pPipelines) { - VkResult result = VK_SUCCESS; - // TODO What to do with pipelineCache? - // The order of operations here is a little convoluted but gets the job done - // 1. Pipeline create state is first shadowed into PIPELINE_NODE struct - // 2. Create state is then validated (which uses flags setup during shadowing) - // 3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap - VkBool32 skipCall = VK_FALSE; - // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic - vector<PIPELINE_NODE *> pPipeNode(count); - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - - uint32_t i = 0; - loader_platform_thread_lock_mutex(&globalLock); - - for (i = 0; i < count; i++) { - pPipeNode[i] = initGraphicsPipeline(dev_data, &pCreateInfos[i]); - skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode, i); - } - - if (VK_FALSE == skipCall) { - loader_platform_thread_unlock_mutex(&globalLock); - result = dev_data->device_dispatch_table->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, - pPipelines); - loader_platform_thread_lock_mutex(&globalLock); - for (i = 0; i < count; i++) { - pPipeNode[i]->pipeline = pPipelines[i]; - dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i]; - } - loader_platform_thread_unlock_mutex(&globalLock); - } else { - for (i = 0; i < count; i++) { - if (pPipeNode[i]) { - // If we allocated a pipeNode, need to clean it up here - delete[] pPipeNode[i]->pVertexBindingDescriptions; - delete[] pPipeNode[i]->pVertexAttributeDescriptions; - delete[] pPipeNode[i]->pAttachments; - delete pPipeNode[i]; - } - } - loader_platform_thread_unlock_mutex(&globalLock); - return VK_ERROR_VALIDATION_FAILED_EXT; - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count, - const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, - VkPipeline *pPipelines) { - VkResult result = VK_SUCCESS; - VkBool32 skipCall = VK_FALSE; - - // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic - vector<PIPELINE_NODE *> pPipeNode(count); - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - - uint32_t i = 0; - loader_platform_thread_lock_mutex(&globalLock); - for (i = 0; i < count; i++) { - // TODO: Verify compute stage bits - - // Create and initialize internal tracking data structure - pPipeNode[i] = new PIPELINE_NODE; - memcpy(&pPipeNode[i]->computePipelineCI, (const void *)&pCreateInfos[i], sizeof(VkComputePipelineCreateInfo)); - - // TODO: Add Compute Pipeline Verification - // skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode[i]); - } - - if (VK_FALSE == skipCall) { - loader_platform_thread_unlock_mutex(&globalLock); - result = dev_data->device_dispatch_table->CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, - pPipelines); - loader_platform_thread_lock_mutex(&globalLock); - for (i = 0; i < count; i++) { - pPipeNode[i]->pipeline = pPipelines[i]; - dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i]; - } - loader_platform_thread_unlock_mutex(&globalLock); - } else { - for (i = 0; i < count; i++) { - // Clean up any locally allocated data structures - delete pPipeNode[i]; - } - loader_platform_thread_unlock_mutex(&globalLock); - return VK_ERROR_VALIDATION_FAILED_EXT; - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreateSampler(device, pCreateInfo, pAllocator, pSampler); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - dev_data->sampleMap[*pSampler] = unique_ptr<SAMPLER_NODE>(new SAMPLER_NODE(pSampler, pCreateInfo)); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout); - if (VK_SUCCESS == result) { - // TODOSC : Capture layout bindings set - LAYOUT_NODE *pNewNode = new LAYOUT_NODE; - if (NULL == pNewNode) { - if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, - (uint64_t)*pSetLayout, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", - "Out of memory while attempting to allocate LAYOUT_NODE in vkCreateDescriptorSetLayout()")) - return VK_ERROR_VALIDATION_FAILED_EXT; - } - memcpy((void *)&pNewNode->createInfo, pCreateInfo, sizeof(VkDescriptorSetLayoutCreateInfo)); - pNewNode->createInfo.pBindings = new VkDescriptorSetLayoutBinding[pCreateInfo->bindingCount]; - memcpy((void *)pNewNode->createInfo.pBindings, pCreateInfo->pBindings, - sizeof(VkDescriptorSetLayoutBinding) * pCreateInfo->bindingCount); - // g++ does not like reserve with size 0 - if (pCreateInfo->bindingCount) - pNewNode->bindingToIndexMap.reserve(pCreateInfo->bindingCount); - uint32_t totalCount = 0; - for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) { - if (!pNewNode->bindingToIndexMap.emplace(pCreateInfo->pBindings[i].binding, i).second) { - if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)*pSetLayout, __LINE__, - DRAWSTATE_INVALID_LAYOUT, "DS", "duplicated binding number in " - "VkDescriptorSetLayoutBinding")) - return VK_ERROR_VALIDATION_FAILED_EXT; - } else { - pNewNode->bindingToIndexMap[pCreateInfo->pBindings[i].binding] = i; - } - totalCount += pCreateInfo->pBindings[i].descriptorCount; - if (pCreateInfo->pBindings[i].pImmutableSamplers) { - VkSampler **ppIS = (VkSampler **)&pNewNode->createInfo.pBindings[i].pImmutableSamplers; - *ppIS = new VkSampler[pCreateInfo->pBindings[i].descriptorCount]; - memcpy(*ppIS, pCreateInfo->pBindings[i].pImmutableSamplers, - pCreateInfo->pBindings[i].descriptorCount * sizeof(VkSampler)); - } - } - pNewNode->layout = *pSetLayout; - pNewNode->startIndex = 0; - if (totalCount > 0) { - pNewNode->descriptorTypes.resize(totalCount); - pNewNode->stageFlags.resize(totalCount); - uint32_t offset = 0; - uint32_t j = 0; - VkDescriptorType dType; - for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) { - dType = pCreateInfo->pBindings[i].descriptorType; - for (j = 0; j < pCreateInfo->pBindings[i].descriptorCount; j++) { - pNewNode->descriptorTypes[offset + j] = dType; - pNewNode->stageFlags[offset + j] = pCreateInfo->pBindings[i].stageFlags; - if ((dType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) || - (dType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) { - pNewNode->dynamicDescriptorCount++; - } - } - offset += j; - } - pNewNode->endIndex = pNewNode->startIndex + totalCount - 1; - } else { // no descriptors - pNewNode->endIndex = 0; - } - // Put new node at Head of global Layer list - loader_platform_thread_lock_mutex(&globalLock); - dev_data->descriptorSetLayoutMap[*pSetLayout] = pNewNode; - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -static bool validatePushConstantSize(const layer_data *dev_data, const uint32_t offset, const uint32_t size, - const char *caller_name) { - bool skipCall = false; - if ((offset + size) > dev_data->physDevProperties.properties.limits.maxPushConstantsSize) { - skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "%s call has push constants with offset %u and size %u that " - "exceeds this device's maxPushConstantSize of %u.", - caller_name, offset, size, dev_data->physDevProperties.properties.limits.maxPushConstantsSize); - } - return skipCall; -} - -VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) { - bool skipCall = false; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - uint32_t i = 0; - for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) { - skipCall |= validatePushConstantSize(dev_data, pCreateInfo->pPushConstantRanges[i].offset, - pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()"); - if ((pCreateInfo->pPushConstantRanges[i].size == 0) || ((pCreateInfo->pPushConstantRanges[i].size & 0x3) != 0)) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "vkCreatePipelineLayout() call has push constant index %u with " - "size %u. Size must be greater than zero and a multiple of 4.", - i, pCreateInfo->pPushConstantRanges[i].size); - } - // TODO : Add warning if ranges overlap - } - VkResult result = dev_data->device_dispatch_table->CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - // TODOSC : Merge capture of the setLayouts per pipeline - PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout]; - plNode.descriptorSetLayouts.resize(pCreateInfo->setLayoutCount); - for (i = 0; i < pCreateInfo->setLayoutCount; ++i) { - plNode.descriptorSetLayouts[i] = pCreateInfo->pSetLayouts[i]; - } - plNode.pushConstantRanges.resize(pCreateInfo->pushConstantRangeCount); - for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) { - plNode.pushConstantRanges[i] = pCreateInfo->pPushConstantRanges[i]; - } - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, - VkDescriptorPool *pDescriptorPool) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool); - if (VK_SUCCESS == result) { - // Insert this pool into Global Pool LL at head - if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, - (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", "Created Descriptor Pool %#" PRIxLEAST64, - (uint64_t)*pDescriptorPool)) - return VK_ERROR_VALIDATION_FAILED_EXT; - DESCRIPTOR_POOL_NODE *pNewNode = new DESCRIPTOR_POOL_NODE(*pDescriptorPool, pCreateInfo); - if (NULL == pNewNode) { - if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, - (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", - "Out of memory while attempting to allocate DESCRIPTOR_POOL_NODE in vkCreateDescriptorPool()")) - return VK_ERROR_VALIDATION_FAILED_EXT; - } else { - loader_platform_thread_lock_mutex(&globalLock); - dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode; - loader_platform_thread_unlock_mutex(&globalLock); - } - } else { - // Need to do anything if pool create fails? - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->ResetDescriptorPool(device, descriptorPool, flags); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - clearDescriptorPool(dev_data, device, descriptorPool, flags); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - - loader_platform_thread_lock_mutex(&globalLock); - // Verify that requested descriptorSets are available in pool - DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool); - if (!pPoolNode) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, - (uint64_t)pAllocateInfo->descriptorPool, __LINE__, DRAWSTATE_INVALID_POOL, "DS", - "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call", - (uint64_t)pAllocateInfo->descriptorPool); - } else { // Make sure pool has all the available descriptors before calling down chain - skipCall |= validate_descriptor_availability_in_pool(dev_data, pPoolNode, pAllocateInfo->descriptorSetCount, - pAllocateInfo->pSetLayouts); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (skipCall) - return VK_ERROR_VALIDATION_FAILED_EXT; - VkResult result = dev_data->device_dispatch_table->AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool); - if (pPoolNode) { - if (pAllocateInfo->descriptorSetCount == 0) { - log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - pAllocateInfo->descriptorSetCount, __LINE__, DRAWSTATE_NONE, "DS", - "AllocateDescriptorSets called with 0 count"); - } - for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; i++) { - log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, - (uint64_t)pDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS", "Created Descriptor Set %#" PRIxLEAST64, - (uint64_t)pDescriptorSets[i]); - // Create new set node and add to head of pool nodes - SET_NODE *pNewNode = new SET_NODE; - if (NULL == pNewNode) { - if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, - DRAWSTATE_OUT_OF_MEMORY, "DS", - "Out of memory while attempting to allocate SET_NODE in vkAllocateDescriptorSets()")) - return VK_ERROR_VALIDATION_FAILED_EXT; - } else { - // TODO : Pool should store a total count of each type of Descriptor available - // When descriptors are allocated, decrement the count and validate here - // that the count doesn't go below 0. One reset/free need to bump count back up. - // Insert set at head of Set LL for this pool - pNewNode->pNext = pPoolNode->pSets; - pNewNode->in_use.store(0); - pPoolNode->pSets = pNewNode; - LAYOUT_NODE *pLayout = getLayoutNode(dev_data, pAllocateInfo->pSetLayouts[i]); - if (NULL == pLayout) { - if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pAllocateInfo->pSetLayouts[i], - __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS", - "Unable to find set layout node for layout %#" PRIxLEAST64 - " specified in vkAllocateDescriptorSets() call", - (uint64_t)pAllocateInfo->pSetLayouts[i])) - return VK_ERROR_VALIDATION_FAILED_EXT; - } - pNewNode->pLayout = pLayout; - pNewNode->pool = pAllocateInfo->descriptorPool; - pNewNode->set = pDescriptorSets[i]; - pNewNode->descriptorCount = (pLayout->createInfo.bindingCount != 0) ? pLayout->endIndex + 1 : 0; - if (pNewNode->descriptorCount) { - size_t descriptorArraySize = sizeof(GENERIC_HEADER *) * pNewNode->descriptorCount; - pNewNode->ppDescriptors = new GENERIC_HEADER *[descriptorArraySize]; - memset(pNewNode->ppDescriptors, 0, descriptorArraySize); - } - dev_data->setMap[pDescriptorSets[i]] = pNewNode; - } - } - } - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count, const VkDescriptorSet *pDescriptorSets) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - // Make sure that no sets being destroyed are in-flight - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < count; ++i) - skipCall |= validateIdleDescriptorSet(dev_data, pDescriptorSets[i], "vkFreeDesriptorSets"); - DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, descriptorPool); - if (pPoolNode && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pPoolNode->createInfo.flags)) { - // Can't Free from a NON_FREE pool - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - (uint64_t)device, __LINE__, DRAWSTATE_CANT_FREE_FROM_NON_FREE_POOL, "DS", - "It is invalid to call vkFreeDescriptorSets() with a pool created without setting " - "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT."); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE != skipCall) - return VK_ERROR_VALIDATION_FAILED_EXT; - VkResult result = dev_data->device_dispatch_table->FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets); - if (VK_SUCCESS == result) { - // For each freed descriptor add it back into the pool as available - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < count; ++i) { - SET_NODE *pSet = dev_data->setMap[pDescriptorSets[i]]; // getSetNode() without locking - invalidateBoundCmdBuffers(dev_data, pSet); - LAYOUT_NODE *pLayout = pSet->pLayout; - uint32_t typeIndex = 0, poolSizeCount = 0; - for (uint32_t j = 0; j < pLayout->createInfo.bindingCount; ++j) { - typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBindings[j].descriptorType); - poolSizeCount = pLayout->createInfo.pBindings[j].descriptorCount; - pPoolNode->availableDescriptorTypeCount[typeIndex] += poolSizeCount; - } - } - loader_platform_thread_unlock_mutex(&globalLock); - } - // TODO : Any other clean-up or book-keeping to do here? - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites, - uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) { - // dsUpdate will return VK_TRUE only if a bailout error occurs, so we want to call down tree when update returns VK_FALSE - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - VkBool32 rtn = dsUpdate(dev_data, device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies); - loader_platform_thread_unlock_mutex(&globalLock); - if (!rtn) { - dev_data->device_dispatch_table->UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, - pDescriptorCopies); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo, VkCommandBuffer *pCommandBuffer) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) { - // Validate command pool - if (dev_data->commandPoolMap.find(pCreateInfo->commandPool) != dev_data->commandPoolMap.end()) { - // Add command buffer to its commandPool map - dev_data->commandPoolMap[pCreateInfo->commandPool].commandBuffers.push_back(pCommandBuffer[i]); - GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE; - // Add command buffer to map - dev_data->commandBufferMap[pCommandBuffer[i]] = pCB; - resetCB(dev_data, pCommandBuffer[i]); - pCB->createInfo = *pCreateInfo; - pCB->device = device; - } - } - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - // Validate command buffer level - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) { - // Secondary Command Buffer - const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo; - if (!pInfo) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", - "vkBeginCommandBuffer(): Secondary Command Buffer (%p) must have inheritance info.", - reinterpret_cast<void *>(commandBuffer)); - } else { - if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) { - if (!pInfo->renderPass) { // renderpass should NOT be null for an Secondary CB - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", - "vkBeginCommandBuffer(): Secondary Command Buffers (%p) must specify a valid renderpass parameter.", - reinterpret_cast<void *>(commandBuffer)); - } - if (!pInfo->framebuffer) { // framebuffer may be null for an Secondary CB, but this affects perf - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, - "DS", "vkBeginCommandBuffer(): Secondary Command Buffers (%p) may perform better if a " - "valid framebuffer parameter is specified.", - reinterpret_cast<void *>(commandBuffer)); - } else { - string errorString = ""; - auto fbNode = dev_data->frameBufferMap.find(pInfo->framebuffer); - if (fbNode != dev_data->frameBufferMap.end()) { - VkRenderPass fbRP = fbNode->second.createInfo.renderPass; - if (!verify_renderpass_compatibility(dev_data, fbRP, pInfo->renderPass, errorString)) { - // renderPass that framebuffer was created with - // must - // be compatible with local renderPass - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, - "DS", "vkBeginCommandBuffer(): Secondary Command " - "Buffer (%p) renderPass (%#" PRIxLEAST64 ") is incompatible w/ framebuffer " - "(%#" PRIxLEAST64 ") w/ render pass (%#" PRIxLEAST64 ") due to: %s", - reinterpret_cast<void *>(commandBuffer), (uint64_t)(pInfo->renderPass), - (uint64_t)(pInfo->framebuffer), (uint64_t)(fbRP), errorString.c_str()); - } - // Connect this framebuffer to this cmdBuffer - fbNode->second.referencingCmdBuffers.insert(pCB->commandBuffer); - } - } - } - if ((pInfo->occlusionQueryEnable == VK_FALSE || - dev_data->physDevProperties.features.occlusionQueryPrecise == VK_FALSE) && - (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer), - __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", - "vkBeginCommandBuffer(): Secondary Command Buffer (%p) must not have " - "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not " - "support precise occlusion queries.", - reinterpret_cast<void *>(commandBuffer)); - } - } - if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) { - auto rp_data = dev_data->renderPassMap.find(pInfo->renderPass); - if (rp_data != dev_data->renderPassMap.end() && rp_data->second && rp_data->second->pCreateInfo) { - if (pInfo->subpass >= rp_data->second->pCreateInfo->subpassCount) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__, - DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", - "vkBeginCommandBuffer(): Secondary Command Buffers (%p) must has a subpass index (%d) " - "that is less than the number of subpasses (%d).", - (void *)commandBuffer, pInfo->subpass, rp_data->second->pCreateInfo->subpassCount); - } - } - } - } - if (CB_RECORDING == pCB->state) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)commandBuffer, __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", - "vkBeginCommandBuffer(): Cannot call Begin on CB (%#" PRIxLEAST64 - ") in the RECORDING state. Must first call vkEndCommandBuffer().", - (uint64_t)commandBuffer); - } else if (CB_RECORDED == pCB->state) { - VkCommandPool cmdPool = pCB->createInfo.commandPool; - if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", - "Call to vkBeginCommandBuffer() on command buffer (%#" PRIxLEAST64 - ") attempts to implicitly reset cmdBuffer created from command pool (%#" PRIxLEAST64 - ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.", - (uint64_t)commandBuffer, (uint64_t)cmdPool); - } - resetCB(dev_data, commandBuffer); - } - // Set updated state here in case implicit reset occurs above - pCB->state = CB_RECORDING; - pCB->beginInfo = *pBeginInfo; - if (pCB->beginInfo.pInheritanceInfo) { - pCB->inheritanceInfo = *(pCB->beginInfo.pInheritanceInfo); - pCB->beginInfo.pInheritanceInfo = &pCB->inheritanceInfo; - } - } else { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", - "In vkBeginCommandBuffer() and unable to find CommandBuffer Node for CB %p!", (void *)commandBuffer); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE != skipCall) { - return VK_ERROR_VALIDATION_FAILED_EXT; - } - VkResult result = dev_data->device_dispatch_table->BeginCommandBuffer(commandBuffer, pBeginInfo); - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(VkCommandBuffer commandBuffer) { - VkBool32 skipCall = VK_FALSE; - VkResult result = VK_SUCCESS; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - if (pCB->state != CB_RECORDING) { - skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkEndCommandBuffer()"); - } - for (auto query : pCB->activeQueries) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_QUERY, "DS", - "Ending command buffer with in progress query: queryPool %" PRIu64 ", index %d", - (uint64_t)(query.pool), query.index); - } - } - if (VK_FALSE == skipCall) { - loader_platform_thread_unlock_mutex(&globalLock); - result = dev_data->device_dispatch_table->EndCommandBuffer(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - if (VK_SUCCESS == result) { - pCB->state = CB_RECORDED; - // Reset CB status flags - pCB->status = 0; - printCB(dev_data, commandBuffer); - } - } else { - result = VK_ERROR_VALIDATION_FAILED_EXT; - } - loader_platform_thread_unlock_mutex(&globalLock); - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - VkCommandPool cmdPool = pCB->createInfo.commandPool; - if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", - "Attempt to reset command buffer (%#" PRIxLEAST64 ") created from command pool (%#" PRIxLEAST64 - ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.", - (uint64_t)commandBuffer, (uint64_t)cmdPool); - } - if (dev_data->globalInFlightCmdBuffers.count(commandBuffer)) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS", - "Attempt to reset command buffer (%#" PRIxLEAST64 ") which is in use.", - reinterpret_cast<uint64_t>(commandBuffer)); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (skipCall != VK_FALSE) - return VK_ERROR_VALIDATION_FAILED_EXT; - VkResult result = dev_data->device_dispatch_table->ResetCommandBuffer(commandBuffer, flags); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - resetCB(dev_data, commandBuffer); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_BINDPIPELINE, "vkCmdBindPipeline()"); - if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (pCB->activeRenderPass)) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, - (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS", - "Incorrectly binding compute pipeline (%#" PRIxLEAST64 ") during active RenderPass (%#" PRIxLEAST64 ")", - (uint64_t)pipeline, (uint64_t)pCB->activeRenderPass); - } - - PIPELINE_NODE *pPN = getPipeline(dev_data, pipeline); - if (pPN) { - pCB->lastBoundPipeline = pipeline; - set_cb_pso_status(pCB, pPN); - skipCall |= validatePipelineState(dev_data, pCB, pipelineBindPoint, pipeline); - } else { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, - (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_PIPELINE, "DS", - "Attempt to bind Pipeline %#" PRIxLEAST64 " that doesn't exist!", (uint64_t)(pipeline)); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()"); - pCB->status |= CBSTATUS_VIEWPORT_SET; - pCB->viewports.resize(viewportCount); - memcpy(pCB->viewports.data(), pViewports, viewportCount * sizeof(VkViewport)); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *pScissors) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()"); - pCB->status |= CBSTATUS_SCISSOR_SET; - pCB->scissors.resize(scissorCount); - memcpy(pCB->scissors.data(), pScissors, scissorCount * sizeof(VkRect2D)); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()"); - pCB->status |= CBSTATUS_LINE_WIDTH_SET; - pCB->lineWidth = lineWidth; - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdSetLineWidth(commandBuffer, lineWidth); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()"); - pCB->status |= CBSTATUS_DEPTH_BIAS_SET; - pCB->depthBiasConstantFactor = depthBiasConstantFactor; - pCB->depthBiasClamp = depthBiasClamp; - pCB->depthBiasSlopeFactor = depthBiasSlopeFactor; - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, - depthBiasSlopeFactor); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()"); - pCB->status |= CBSTATUS_BLEND_SET; - memcpy(pCB->blendConstants, blendConstants, 4 * sizeof(float)); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdSetBlendConstants(commandBuffer, blendConstants); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()"); - pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET; - pCB->minDepthBounds = minDepthBounds; - pCB->maxDepthBounds = maxDepthBounds; - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()"); - if (faceMask & VK_STENCIL_FACE_FRONT_BIT) { - pCB->front.compareMask = compareMask; - } - if (faceMask & VK_STENCIL_FACE_BACK_BIT) { - pCB->back.compareMask = compareMask; - } - /* TODO: Do we need to track front and back separately? */ - /* TODO: We aren't capturing the faceMask, do we need to? */ - pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET; - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()"); - if (faceMask & VK_STENCIL_FACE_FRONT_BIT) { - pCB->front.writeMask = writeMask; - } - if (faceMask & VK_STENCIL_FACE_BACK_BIT) { - pCB->back.writeMask = writeMask; - } - pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET; - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()"); - if (faceMask & VK_STENCIL_FACE_FRONT_BIT) { - pCB->front.reference = reference; - } - if (faceMask & VK_STENCIL_FACE_BACK_BIT) { - pCB->back.reference = reference; - } - pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET; - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdSetStencilReference(commandBuffer, faceMask, reference); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, - uint32_t firstSet, uint32_t setCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount, - const uint32_t *pDynamicOffsets) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - if (pCB->state == CB_RECORDING) { - if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (pCB->activeRenderPass)) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS", - "Incorrectly binding compute DescriptorSets during active RenderPass (%#" PRIxLEAST64 ")", - (uint64_t)pCB->activeRenderPass); - } else if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) { - skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdBindDescriptorSets"); - } - if (VK_FALSE == skipCall) { - // Track total count of dynamic descriptor types to make sure we have an offset for each one - uint32_t totalDynamicDescriptors = 0; - string errorString = ""; - uint32_t lastSetIndex = firstSet + setCount - 1; - if (lastSetIndex >= pCB->boundDescriptorSets.size()) - pCB->boundDescriptorSets.resize(lastSetIndex + 1); - VkDescriptorSet oldFinalBoundSet = pCB->boundDescriptorSets[lastSetIndex]; - for (uint32_t i = 0; i < setCount; i++) { - SET_NODE *pSet = getSetNode(dev_data, pDescriptorSets[i]); - if (pSet) { - pCB->uniqueBoundSets.insert(pDescriptorSets[i]); - pSet->boundCmdBuffers.insert(commandBuffer); - pCB->lastBoundDescriptorSet = pDescriptorSets[i]; - pCB->lastBoundPipelineLayout = layout; - pCB->boundDescriptorSets[i + firstSet] = pDescriptorSets[i]; - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, - DRAWSTATE_NONE, "DS", "DS %#" PRIxLEAST64 " bound on pipeline %s", - (uint64_t)pDescriptorSets[i], string_VkPipelineBindPoint(pipelineBindPoint)); - if (!pSet->pUpdateStructs && (pSet->descriptorCount != 0)) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], - __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS", - "DS %#" PRIxLEAST64 - " bound but it was never updated. You may want to either update it or not bind it.", - (uint64_t)pDescriptorSets[i]); - } - // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout - if (!verify_set_layout_compatibility(dev_data, pSet, layout, i + firstSet, errorString)) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], - __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS", - "descriptorSet #%u being bound is not compatible with overlapping layout in " - "pipelineLayout due to: %s", - i, errorString.c_str()); - } - if (pSet->pLayout->dynamicDescriptorCount) { - // First make sure we won't overstep bounds of pDynamicOffsets array - if ((totalDynamicDescriptors + pSet->pLayout->dynamicDescriptorCount) > dynamicOffsetCount) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, - DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS", - "descriptorSet #%u (%#" PRIxLEAST64 - ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets " - "array. There must be one dynamic offset for each dynamic descriptor being bound.", - i, (uint64_t)pDescriptorSets[i], pSet->pLayout->dynamicDescriptorCount, - (dynamicOffsetCount - totalDynamicDescriptors)); - } else { // Validate and store dynamic offsets with the set - // Validate Dynamic Offset Minimums - uint32_t cur_dyn_offset = totalDynamicDescriptors; - for (uint32_t d = 0; d < pSet->descriptorCount; d++) { - if (pSet->pLayout->descriptorTypes[d] == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { - if (vk_safe_modulo( - pDynamicOffsets[cur_dyn_offset], - dev_data->physDevProperties.properties.limits.minUniformBufferOffsetAlignment) != - 0) { - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, - DRAWSTATE_INVALID_UNIFORM_BUFFER_OFFSET, "DS", - "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of " - "device limit minUniformBufferOffsetAlignment %#" PRIxLEAST64, - cur_dyn_offset, pDynamicOffsets[cur_dyn_offset], - dev_data->physDevProperties.properties.limits.minUniformBufferOffsetAlignment); - } - cur_dyn_offset++; - } else if (pSet->pLayout->descriptorTypes[d] == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) { - if (vk_safe_modulo( - pDynamicOffsets[cur_dyn_offset], - dev_data->physDevProperties.properties.limits.minStorageBufferOffsetAlignment) != - 0) { - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, - DRAWSTATE_INVALID_STORAGE_BUFFER_OFFSET, "DS", - "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of " - "device limit minStorageBufferOffsetAlignment %#" PRIxLEAST64, - cur_dyn_offset, pDynamicOffsets[cur_dyn_offset], - dev_data->physDevProperties.properties.limits.minStorageBufferOffsetAlignment); - } - cur_dyn_offset++; - } - } - // Keep running total of dynamic descriptor count to verify at the end - totalDynamicDescriptors += pSet->pLayout->dynamicDescriptorCount; - } - } - } else { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__, - DRAWSTATE_INVALID_SET, "DS", "Attempt to bind DS %#" PRIxLEAST64 " that doesn't exist!", - (uint64_t)pDescriptorSets[i]); - } - } - skipCall |= addCmd(dev_data, pCB, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescrsiptorSets()"); - // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update - if (firstSet > 0) { // Check set #s below the first bound set - for (uint32_t i = 0; i < firstSet; ++i) { - if (pCB->boundDescriptorSets[i] && - !verify_set_layout_compatibility(dev_data, dev_data->setMap[pCB->boundDescriptorSets[i]], layout, i, - errorString)) { - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pCB->boundDescriptorSets[i], __LINE__, - DRAWSTATE_NONE, "DS", - "DescriptorSetDS %#" PRIxLEAST64 - " previously bound as set #%u was disturbed by newly bound pipelineLayout (%#" PRIxLEAST64 ")", - (uint64_t)pCB->boundDescriptorSets[i], i, (uint64_t)layout); - pCB->boundDescriptorSets[i] = VK_NULL_HANDLE; - } - } - } - // Check if newly last bound set invalidates any remaining bound sets - if ((pCB->boundDescriptorSets.size() - 1) > (lastSetIndex)) { - if (oldFinalBoundSet && - !verify_set_layout_compatibility(dev_data, dev_data->setMap[oldFinalBoundSet], layout, lastSetIndex, - errorString)) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)oldFinalBoundSet, __LINE__, - DRAWSTATE_NONE, "DS", "DescriptorSetDS %#" PRIxLEAST64 - " previously bound as set #%u is incompatible with set %#" PRIxLEAST64 - " newly bound as set #%u so set #%u and any subsequent sets were " - "disturbed by newly bound pipelineLayout (%#" PRIxLEAST64 ")", - (uint64_t)oldFinalBoundSet, lastSetIndex, (uint64_t)pCB->boundDescriptorSets[lastSetIndex], - lastSetIndex, lastSetIndex + 1, (uint64_t)layout); - pCB->boundDescriptorSets.resize(lastSetIndex + 1); - } - } - // dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound - if (totalDynamicDescriptors != dynamicOffsetCount) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__, - DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS", - "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount " - "is %u. It should exactly match the number of dynamic descriptors.", - setCount, totalDynamicDescriptors, dynamicOffsetCount); - } - // Save dynamicOffsets bound to this CB - for (uint32_t i = 0; i < dynamicOffsetCount; i++) { - pCB->dynamicOffsets.emplace_back(pDynamicOffsets[i]); - } - } - } else { - skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindDescriptorSets()"); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount, - pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()"); - VkDeviceSize offset_align = 0; - switch (indexType) { - case VK_INDEX_TYPE_UINT16: - offset_align = 2; - break; - case VK_INDEX_TYPE_UINT32: - offset_align = 4; - break; - default: - // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0 - break; - } - if (!offset_align || (offset % offset_align)) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS", - "vkCmdBindIndexBuffer() offset (%#" PRIxLEAST64 ") does not fall on alignment (%s) boundary.", - offset, string_VkIndexType(indexType)); - } - pCB->status |= CBSTATUS_INDEX_BUFFER_BOUND; - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType); -} - -void updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) { - uint32_t end = firstBinding + bindingCount; - if (pCB->currentDrawData.buffers.size() < end) { - pCB->currentDrawData.buffers.resize(end); - } - for (uint32_t i = 0; i < bindingCount; ++i) { - pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i]; - } -} - -void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); } - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, - uint32_t bindingCount, const VkBuffer *pBuffers, - const VkDeviceSize *pOffsets) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - addCmd(dev_data, pCB, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffer()"); - updateResourceTracking(pCB, firstBinding, bindingCount, pBuffers); - } else { - skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindVertexBuffer()"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, - uint32_t firstVertex, uint32_t firstInstance) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_DRAW, "vkCmdDraw()"); - pCB->drawCount[DRAW]++; - skipCall |= validate_draw_state(dev_data, pCB, VK_FALSE); - // TODO : Need to pass commandBuffer as srcObj here - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, - __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDraw() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW]++); - skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); - if (VK_FALSE == skipCall) { - updateResourceTrackingOnDraw(pCB); - } - skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDraw"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, - uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, - uint32_t firstInstance) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - VkBool32 skipCall = VK_FALSE; - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXED, "vkCmdDrawIndexed()"); - pCB->drawCount[DRAW_INDEXED]++; - skipCall |= validate_draw_state(dev_data, pCB, VK_TRUE); - // TODO : Need to pass commandBuffer as srcObj here - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS", - "vkCmdDrawIndexed() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW_INDEXED]++); - skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); - if (VK_FALSE == skipCall) { - updateResourceTrackingOnDraw(pCB); - } - skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexed"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, - firstInstance); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - VkBool32 skipCall = VK_FALSE; - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDIRECT, "vkCmdDrawIndirect()"); - pCB->drawCount[DRAW_INDIRECT]++; - skipCall |= validate_draw_state(dev_data, pCB, VK_FALSE); - // TODO : Need to pass commandBuffer as srcObj here - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS", - "vkCmdDrawIndirect() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW_INDIRECT]++); - skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); - if (VK_FALSE == skipCall) { - updateResourceTrackingOnDraw(pCB); - } - skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndirect"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdDrawIndirect(commandBuffer, buffer, offset, count, stride); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXEDINDIRECT, "vkCmdDrawIndexedIndirect()"); - pCB->drawCount[DRAW_INDEXED_INDIRECT]++; - loader_platform_thread_unlock_mutex(&globalLock); - skipCall |= validate_draw_state(dev_data, pCB, VK_TRUE); - loader_platform_thread_lock_mutex(&globalLock); - // TODO : Need to pass commandBuffer as srcObj here - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, - __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDrawIndexedIndirect() call #%" PRIu64 ", reporting DS state:", - g_drawCount[DRAW_INDEXED_INDIRECT]++); - skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer); - if (VK_FALSE == skipCall) { - updateResourceTrackingOnDraw(pCB); - } - skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexedIndirect"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_DISPATCH, "vkCmdDispatch()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatch"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdDispatch(commandBuffer, x, y, z); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_DISPATCHINDIRECT, "vkCmdDispatchIndirect()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatchIndirect"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdDispatchIndirect(commandBuffer, buffer, offset); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, - uint32_t regionCount, const VkBufferCopy *pRegions) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_COPYBUFFER, "vkCmdCopyBuffer()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyBuffer"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); -} - -VkBool32 VerifySourceImageLayout(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageSubresourceLayers subLayers, - VkImageLayout srcImageLayout) { - VkBool32 skip_call = VK_FALSE; - - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); - for (uint32_t i = 0; i < subLayers.layerCount; ++i) { - uint32_t layer = i + subLayers.baseArrayLayer; - VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer}; - IMAGE_CMD_BUF_LAYOUT_NODE node; - if (!FindLayout(pCB, srcImage, sub, node)) { - SetLayout(pCB, srcImage, sub, {srcImageLayout, srcImageLayout}); - continue; - } - if (node.layout != srcImageLayout) { - // TODO: Improve log message in the next pass - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, - __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose source layout is %s " - "and doesn't match the current layout %s.", - string_VkImageLayout(srcImageLayout), string_VkImageLayout(node.layout)); - } - } - if (srcImageLayout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - if (srcImageLayout == VK_IMAGE_LAYOUT_GENERAL) { - // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning. - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, - 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", - "Layout for input image should be TRANSFER_SRC_OPTIMAL instead of GENERAL."); - } else { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for input image is %s but can only be " - "TRANSFER_SRC_OPTIMAL or GENERAL.", - string_VkImageLayout(srcImageLayout)); - } - } - return skip_call; -} - -VkBool32 VerifyDestImageLayout(VkCommandBuffer cmdBuffer, VkImage destImage, VkImageSubresourceLayers subLayers, - VkImageLayout destImageLayout) { - VkBool32 skip_call = VK_FALSE; - - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); - for (uint32_t i = 0; i < subLayers.layerCount; ++i) { - uint32_t layer = i + subLayers.baseArrayLayer; - VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer}; - IMAGE_CMD_BUF_LAYOUT_NODE node; - if (!FindLayout(pCB, destImage, sub, node)) { - SetLayout(pCB, destImage, sub, {destImageLayout, destImageLayout}); - continue; - } - if (node.layout != destImageLayout) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, - __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose dest layout is %s and " - "doesn't match the current layout %s.", - string_VkImageLayout(destImageLayout), string_VkImageLayout(node.layout)); - } - } - if (destImageLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - if (destImageLayout == VK_IMAGE_LAYOUT_GENERAL) { - // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning. - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, - 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", - "Layout for output image should be TRANSFER_DST_OPTIMAL instead of GENERAL."); - } else { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for output image is %s but can only be " - "TRANSFER_DST_OPTIMAL or GENERAL.", - string_VkImageLayout(destImageLayout)); - } - } - return skip_call; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, - VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_COPYIMAGE, "vkCmdCopyImage()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyImage"); - for (uint32_t i = 0; i < regionCount; ++i) { - skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].srcSubresource, srcImageLayout); - skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].dstSubresource, dstImageLayout); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, - regionCount, pRegions); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, - VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_BLITIMAGE, "vkCmdBlitImage()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdBlitImage"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, - regionCount, pRegions, filter); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, - VkImage dstImage, VkImageLayout dstImageLayout, - uint32_t regionCount, const VkBufferImageCopy *pRegions) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyBufferToImage"); - for (uint32_t i = 0; i < regionCount; ++i) { - skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].imageSubresource, dstImageLayout); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, - pRegions); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, - VkImageLayout srcImageLayout, VkBuffer dstBuffer, - uint32_t regionCount, const VkBufferImageCopy *pRegions) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyImageToBuffer"); - for (uint32_t i = 0; i < regionCount; ++i) { - skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].imageSubresource, srcImageLayout); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, - pRegions); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, - VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t *pData) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyUpdateBuffer"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_FILLBUFFER, "vkCmdFillBuffer()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyFillBuffer"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, - const VkClearAttachment *pAttachments, uint32_t rectCount, - const VkClearRect *pRects) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()"); - // Warn if this is issued prior to Draw Cmd and clearing the entire attachment - if (!hasDrawCmd(pCB) && (pCB->activeRenderPassBeginInfo.renderArea.extent.width == pRects[0].rect.extent.width) && - (pCB->activeRenderPassBeginInfo.renderArea.extent.height == pRects[0].rect.extent.height)) { - // TODO : commandBuffer should be srcObj - // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass) - // 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 - // call CmdClearAttachments - // Otherwise this seems more like a performance warning. - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 0, DRAWSTATE_CLEAR_CMD_BEFORE_DRAW, "DS", - "vkCmdClearAttachments() issued on CB object 0x%" PRIxLEAST64 " prior to any Draw Cmds." - " It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.", - (uint64_t)(commandBuffer)); - } - skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdClearAttachments"); - } - - // Validate that attachment is in reference list of active subpass - if (pCB->activeRenderPass) { - const VkRenderPassCreateInfo *pRPCI = dev_data->renderPassMap[pCB->activeRenderPass]->pCreateInfo; - const VkSubpassDescription *pSD = &pRPCI->pSubpasses[pCB->activeSubpass]; - - for (uint32_t attachment_idx = 0; attachment_idx < attachmentCount; attachment_idx++) { - const VkClearAttachment *attachment = &pAttachments[attachment_idx]; - if (attachment->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { - VkBool32 found = VK_FALSE; - for (uint32_t i = 0; i < pSD->colorAttachmentCount; i++) { - if (attachment->colorAttachment == pSD->pColorAttachments[i].attachment) { - found = VK_TRUE; - break; - } - } - if (VK_FALSE == found) { - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS", - "vkCmdClearAttachments() attachment index %d not found in attachment reference array of active subpass %d", - attachment->colorAttachment, pCB->activeSubpass); - } - } else if (attachment->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - if (!pSD->pDepthStencilAttachment || // Says no DS will be used in active subpass - (pSD->pDepthStencilAttachment->attachment == - VK_ATTACHMENT_UNUSED)) { // Says no DS will be used in active subpass - - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS", - "vkCmdClearAttachments() attachment index %d does not match depthStencilAttachment.attachment (%d) found " - "in active subpass %d", - attachment->colorAttachment, - (pSD->pDepthStencilAttachment) ? pSD->pDepthStencilAttachment->attachment : VK_ATTACHMENT_UNUSED, - pCB->activeSubpass); - } - } - } - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, - VkImageLayout imageLayout, const VkClearColorValue *pColor, - uint32_t rangeCount, const VkImageSubresourceRange *pRanges) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdClearColorImage"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, - const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount, - const VkImageSubresourceRange *pRanges) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdClearDepthStencilImage"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, - pRanges); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, - VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve *pRegions) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_RESOLVEIMAGE, "vkCmdResolveImage()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdResolveImage"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, - regionCount, pRegions); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent"); - pCB->events.push_back(event); - pCB->eventToStageMap[event] = stageMask; - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdSetEvent(commandBuffer, event, stageMask); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()"); - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent"); - pCB->events.push_back(event); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdResetEvent(commandBuffer, event, stageMask); -} - -VkBool32 TransitionImageLayouts(VkCommandBuffer cmdBuffer, uint32_t memBarrierCount, const VkImageMemoryBarrier *pImgMemBarriers) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); - VkBool32 skip = VK_FALSE; - uint32_t levelCount = 0; - uint32_t layerCount = 0; - - for (uint32_t i = 0; i < memBarrierCount; ++i) { - auto mem_barrier = &pImgMemBarriers[i]; - if (!mem_barrier) - continue; - // TODO: Do not iterate over every possibility - consolidate where - // possible - ResolveRemainingLevelsLayers(dev_data, &levelCount, &layerCount, mem_barrier->subresourceRange, mem_barrier->image); - - for (uint32_t j = 0; j < levelCount; j++) { - uint32_t level = mem_barrier->subresourceRange.baseMipLevel + j; - for (uint32_t k = 0; k < layerCount; k++) { - uint32_t layer = mem_barrier->subresourceRange.baseArrayLayer + k; - VkImageSubresource sub = {mem_barrier->subresourceRange.aspectMask, level, layer}; - IMAGE_CMD_BUF_LAYOUT_NODE node; - if (!FindLayout(pCB, mem_barrier->image, sub, node)) { - SetLayout(pCB, mem_barrier->image, sub, {mem_barrier->oldLayout, mem_barrier->newLayout}); - continue; - } - if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) { - // TODO: Set memory invalid which is in mem_tracker currently - } else if (node.layout != mem_barrier->oldLayout) { - skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "You cannot transition the layout from %s " - "when current layout is %s.", - string_VkImageLayout(mem_barrier->oldLayout), string_VkImageLayout(node.layout)); - } - SetLayout(pCB, mem_barrier->image, sub, mem_barrier->newLayout); - } - } - } - return skip; -} - -// Print readable FlagBits in FlagMask -std::string string_VkAccessFlags(VkAccessFlags accessMask) { - std::string result; - std::string separator; - - if (accessMask == 0) { - result = "[None]"; - } else { - result = "["; - for (auto i = 0; i < 32; i++) { - if (accessMask & (1 << i)) { - result = result + separator + string_VkAccessFlagBits((VkAccessFlagBits)(1 << i)); - separator = " | "; - } - } - result = result + "]"; - } - return result; -} - -// AccessFlags MUST have 'required_bit' set, and may have one or more of 'optional_bits' set. -// If required_bit is zero, accessMask must have at least one of 'optional_bits' set -// TODO: Add tracking to ensure that at least one barrier has been set for these layout transitions -VkBool32 ValidateMaskBits(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask, - const VkImageLayout &layout, VkAccessFlags required_bit, VkAccessFlags optional_bits, const char *type) { - VkBool32 skip_call = VK_FALSE; - - if ((accessMask & required_bit) || (!required_bit && (accessMask & optional_bits))) { - if (accessMask & !(required_bit | optional_bits)) { - // TODO: Verify against Valid Use - skip_call |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask %d %s are specified when layout is %s.", - type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout)); - } - } else { - if (!required_bit) { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must contain at least one of access bits %d " - "%s when layout is %s, unless the app has previously added a " - "barrier for this transition.", - type, accessMask, string_VkAccessFlags(accessMask).c_str(), optional_bits, - string_VkAccessFlags(optional_bits).c_str(), string_VkImageLayout(layout)); - } else { - std::string opt_bits; - if (optional_bits != 0) { - std::stringstream ss; - ss << optional_bits; - opt_bits = "and may have optional bits " + ss.str() + ' ' + string_VkAccessFlags(optional_bits); - } - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must have required access bit %d %s %s when " - "layout is %s, unless the app has previously added a barrier for " - "this transition.", - type, accessMask, string_VkAccessFlags(accessMask).c_str(), required_bit, - string_VkAccessFlags(required_bit).c_str(), opt_bits.c_str(), string_VkImageLayout(layout)); - } - } - return skip_call; -} - -VkBool32 ValidateMaskBitsFromLayouts(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask, - const VkImageLayout &layout, const char *type) { - VkBool32 skip_call = VK_FALSE; - switch (layout) { - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: { - skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, type); - break; - } - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: { - skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, type); - break; - } - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: { - skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_WRITE_BIT, 0, type); - break; - } - case VK_IMAGE_LAYOUT_PREINITIALIZED: { - skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_HOST_WRITE_BIT, 0, type); - break; - } - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: { - skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type); - break; - } - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: { - skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0, - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type); - break; - } - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: { - skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_READ_BIT, 0, type); - break; - } - case VK_IMAGE_LAYOUT_UNDEFINED: { - if (accessMask != 0) { - // TODO: Verify against Valid Use section spec - skip_call |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask %d %s are specified when layout is %s.", - type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout)); - } - break; - } - case VK_IMAGE_LAYOUT_GENERAL: - default: { break; } - } - return skip_call; -} - -VkBool32 ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount, - const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount, - const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount, - const VkImageMemoryBarrier *pImageMemBarriers) { - VkBool32 skip_call = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); - if (pCB->activeRenderPass && memBarrierCount) { - if (!dev_data->renderPassMap[pCB->activeRenderPass]->hasSelfDependency[pCB->activeSubpass]) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_BARRIER, "DS", "%s: Barriers cannot be set during subpass %d " - "with no self dependency specified.", - funcName, pCB->activeSubpass); - } - } - for (uint32_t i = 0; i < imageMemBarrierCount; ++i) { - auto mem_barrier = &pImageMemBarriers[i]; - auto image_data = dev_data->imageMap.find(mem_barrier->image); - if (image_data != dev_data->imageMap.end()) { - uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex; - uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex; - if (image_data->second.createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) { - // srcQueueFamilyIndex and dstQueueFamilyIndex must both - // be VK_QUEUE_FAMILY_IGNORED - if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS", - "%s: Image Barrier for image 0x%" PRIx64 " was created with sharingMode of " - "VK_SHARING_MODE_CONCURRENT. Src and dst " - " queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.", - funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image)); - } - } else { - // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and - // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED, - // or both be a valid queue family - if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) && - (src_q_f_index != dst_q_f_index)) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64 " was created with sharingMode " - "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or " - "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both " - "must be.", - funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image)); - } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) && - ((src_q_f_index >= dev_data->physDevProperties.queue_family_properties.size()) || - (dst_q_f_index >= dev_data->physDevProperties.queue_family_properties.size()))) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS", - "%s: Image 0x%" PRIx64 " was created with sharingMode " - "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d" - " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER - "queueFamilies crated for this device.", - funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image), src_q_f_index, - dst_q_f_index, dev_data->physDevProperties.queue_family_properties.size()); - } - } - } - - if (mem_barrier) { - skip_call |= - ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source"); - skip_call |= - ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest"); - if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) { - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image Layout cannot be transitioned to UNDEFINED or " - "PREINITIALIZED.", - funcName); - } - auto image_data = dev_data->imageMap.find(mem_barrier->image); - VkFormat format; - uint32_t arrayLayers, mipLevels; - bool imageFound = false; - if (image_data != dev_data->imageMap.end()) { - format = image_data->second.createInfo.format; - arrayLayers = image_data->second.createInfo.arrayLayers; - mipLevels = image_data->second.createInfo.mipLevels; - imageFound = true; - } else if (dev_data->device_extensions.wsi_enabled) { - auto imageswap_data = dev_data->device_extensions.imageToSwapchainMap.find(mem_barrier->image); - if (imageswap_data != dev_data->device_extensions.imageToSwapchainMap.end()) { - auto swapchain_data = dev_data->device_extensions.swapchainMap.find(imageswap_data->second); - if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) { - format = swapchain_data->second->createInfo.imageFormat; - arrayLayers = swapchain_data->second->createInfo.imageArrayLayers; - mipLevels = 1; - imageFound = true; - } - } - } - if (imageFound) { - if (vk_format_is_depth_and_stencil(format) && - (!(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) || - !(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT))) { - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image is a depth and stencil format and thus must " - "have both VK_IMAGE_ASPECT_DEPTH_BIT and " - "VK_IMAGE_ASPECT_STENCIL_BIT set.", - funcName); - } - if ((mem_barrier->subresourceRange.baseArrayLayer + mem_barrier->subresourceRange.layerCount) > arrayLayers) { - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the " - "baseArrayLayer (%d) and layerCount (%d) be less " - "than or equal to the total number of layers (%d).", - funcName, mem_barrier->subresourceRange.baseArrayLayer, mem_barrier->subresourceRange.layerCount, - arrayLayers); - } - if ((mem_barrier->subresourceRange.baseMipLevel + mem_barrier->subresourceRange.levelCount) > mipLevels) { - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the baseMipLevel " - "(%d) and levelCount (%d) be less than or equal to " - "the total number of levels (%d).", - funcName, mem_barrier->subresourceRange.baseMipLevel, mem_barrier->subresourceRange.levelCount, - mipLevels); - } - } - } - } - for (uint32_t i = 0; i < bufferBarrierCount; ++i) { - auto mem_barrier = &pBufferMemBarriers[i]; - if (pCB->activeRenderPass) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barriers cannot be used during a render pass.", funcName); - } - if (!mem_barrier) - continue; - - // Validate buffer barrier queue family indices - if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED && - mem_barrier->srcQueueFamilyIndex >= dev_data->physDevProperties.queue_family_properties.size()) || - (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED && - mem_barrier->dstQueueFamilyIndex >= dev_data->physDevProperties.queue_family_properties.size())) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_QUEUE_INDEX, "DS", - "%s: Buffer Barrier 0x%" PRIx64 " has QueueFamilyIndex greater " - "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.", - funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer), - dev_data->physDevProperties.queue_family_properties.size()); - } - - auto buffer_data = dev_data->bufferMap.find(mem_barrier->buffer); - uint64_t buffer_size = - buffer_data->second.create_info ? reinterpret_cast<uint64_t &>(buffer_data->second.create_info->size) : 0; - if (buffer_data != dev_data->bufferMap.end()) { - if (mem_barrier->offset >= buffer_size) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset %" PRIu64 - " whose sum is not less than total size %" PRIu64 ".", - funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer), - reinterpret_cast<const uint64_t &>(mem_barrier->offset), buffer_size); - } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_INVALID_BARRIER, "DS", - "%s: Buffer Barrier 0x%" PRIx64 " has offset %" PRIu64 " and size %" PRIu64 - " whose sum is greater than total size %" PRIu64 ".", - funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer), - reinterpret_cast<const uint64_t &>(mem_barrier->offset), - reinterpret_cast<const uint64_t &>(mem_barrier->size), buffer_size); - } - } - } - return skip_call; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags sourceStageMask, - VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - VkPipelineStageFlags stageMask = 0; - for (uint32_t i = 0; i < eventCount; ++i) { - pCB->waitedEvents.push_back(pEvents[i]); - pCB->events.push_back(pEvents[i]); - auto event_data = pCB->eventToStageMap.find(pEvents[i]); - if (event_data != pCB->eventToStageMap.end()) { - stageMask |= event_data->second; - } else { - auto global_event_data = dev_data->eventMap.find(pEvents[i]); - if (global_event_data == dev_data->eventMap.end()) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT, - reinterpret_cast<const uint64_t &>(pEvents[i]), __LINE__, DRAWSTATE_INVALID_FENCE, "DS", - "Fence 0x%" PRIx64 " cannot be waited on if it has never been set.", - reinterpret_cast<const uint64_t &>(pEvents[i])); - } else { - stageMask |= global_event_data->second.stageMask; - } - } - } - if (sourceStageMask != stageMask) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_FENCE, "DS", "srcStageMask in vkCmdWaitEvents must be the bitwise OR of the " - "stageMask parameters used in calls to vkCmdSetEvent and " - "VK_PIPELINE_STAGE_HOST_BIT if used with vkSetEvent."); - } - if (pCB->state == CB_RECORDING) { - skipCall |= addCmd(dev_data, pCB, CMD_WAITEVENTS, "vkCmdWaitEvents()"); - } else { - skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWaitEvents()"); - } - skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers); - skipCall |= - ValidateBarriers("vkCmdWaitEvents", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, - pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask, - memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, - pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, - VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - skipCall |= addCmd(dev_data, pCB, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()"); - skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers); - skipCall |= - ValidateBarriers("vkCmdPipelineBarrier", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, - pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, - memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, - pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - QueryObject query = {queryPool, slot}; - pCB->activeQueries.insert(query); - if (!pCB->startedQueries.count(query)) { - pCB->startedQueries.insert(query); - } - skipCall |= addCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdBeginQuery(commandBuffer, queryPool, slot, flags); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - QueryObject query = {queryPool, slot}; - if (!pCB->activeQueries.count(query)) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_QUERY, "DS", "Ending a query before it was started: queryPool %" PRIu64 ", index %d", - (uint64_t)(queryPool), slot); - } else { - pCB->activeQueries.erase(query); - } - pCB->queryToStateMap[query] = 1; - if (pCB->state == CB_RECORDING) { - skipCall |= addCmd(dev_data, pCB, CMD_ENDQUERY, "VkCmdEndQuery()"); - } else { - skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdEndQuery()"); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdEndQuery(commandBuffer, queryPool, slot); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - for (uint32_t i = 0; i < queryCount; i++) { - QueryObject query = {queryPool, firstQuery + i}; - pCB->waitedEventsBeforeQueryReset[query] = pCB->waitedEvents; - pCB->queryToStateMap[query] = 0; - } - if (pCB->state == CB_RECORDING) { - skipCall |= addCmd(dev_data, pCB, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()"); - } else { - skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdResetQueryPool()"); - } - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdQueryPool"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, - VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - for (uint32_t i = 0; i < queryCount; i++) { - QueryObject query = {queryPool, firstQuery + i}; - if (!pCB->queryToStateMap[query]) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_INVALID_QUERY, "DS", - "Requesting a copy from query to buffer with invalid query: queryPool %" PRIu64 ", index %d", - (uint64_t)(queryPool), firstQuery + i); - } - } - if (pCB->state == CB_RECORDING) { - skipCall |= addCmd(dev_data, pCB, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()"); - } else { - skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdCopyQueryPoolResults()"); - } - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyQueryPoolResults"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, - dstOffset, stride, flags); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, - VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, - const void *pValues) { - bool skipCall = false; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - if (pCB->state == CB_RECORDING) { - skipCall |= addCmd(dev_data, pCB, CMD_PUSHCONSTANTS, "vkCmdPushConstants()"); - } else { - skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdPushConstants()"); - } - } - if ((offset + size) > dev_data->physDevProperties.properties.limits.maxPushConstantsSize) { - skipCall |= validatePushConstantSize(dev_data, offset, size, "vkCmdPushConstants()"); - } - // TODO : Add warning if push constant update doesn't align with range - loader_platform_thread_unlock_mutex(&globalLock); - if (!skipCall) - dev_data->device_dispatch_table->CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t slot) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - QueryObject query = {queryPool, slot}; - pCB->queryToStateMap[query] = 1; - if (pCB->state == CB_RECORDING) { - skipCall |= addCmd(dev_data, pCB, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()"); - } else { - skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWriteTimestamp()"); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkFramebuffer *pFramebuffer) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer); - if (VK_SUCCESS == result) { - // Shadow create info and store in map - VkFramebufferCreateInfo *localFBCI = new VkFramebufferCreateInfo(*pCreateInfo); - if (pCreateInfo->pAttachments) { - localFBCI->pAttachments = new VkImageView[localFBCI->attachmentCount]; - memcpy((void *)localFBCI->pAttachments, pCreateInfo->pAttachments, localFBCI->attachmentCount * sizeof(VkImageView)); - } - FRAMEBUFFER_NODE fbNode = {}; - fbNode.createInfo = *localFBCI; - std::pair<VkFramebuffer, FRAMEBUFFER_NODE> fbPair(*pFramebuffer, fbNode); - loader_platform_thread_lock_mutex(&globalLock); - dev_data->frameBufferMap.insert(fbPair); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VkBool32 FindDependency(const int index, const int dependent, const std::vector<DAGNode> &subpass_to_node, - std::unordered_set<uint32_t> &processed_nodes) { - // If we have already checked this node we have not found a dependency path so return false. - if (processed_nodes.count(index)) - return VK_FALSE; - processed_nodes.insert(index); - const DAGNode &node = subpass_to_node[index]; - // Look for a dependency path. If one exists return true else recurse on the previous nodes. - if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) { - for (auto elem : node.prev) { - if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) - return VK_TRUE; - } - } else { - return VK_TRUE; - } - return VK_FALSE; -} - -VkBool32 CheckDependencyExists(const layer_data *my_data, const int subpass, const std::vector<uint32_t> &dependent_subpasses, - const std::vector<DAGNode> &subpass_to_node, VkBool32 &skip_call) { - VkBool32 result = VK_TRUE; - // Loop through all subpasses that share the same attachment and make sure a dependency exists - for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) { - if (subpass == dependent_subpasses[k]) - continue; - const DAGNode &node = subpass_to_node[subpass]; - // Check for a specified dependency between the two nodes. If one exists we are done. - auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]); - auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]); - if (prev_elem == node.prev.end() && next_elem == node.next.end()) { - // If no dependency exits an implicit dependency still might. If so, warn and if not throw an error. - std::unordered_set<uint32_t> processed_nodes; - if (FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) || - FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes)) { - // TODO: Verify against Valid Use section of spec - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS", - "A dependency between subpasses %d and %d must exist but only an implicit one is specified.", - subpass, dependent_subpasses[k]); - } else { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS", - "A dependency between subpasses %d and %d must exist but one is not specified.", subpass, - dependent_subpasses[k]); - result = VK_FALSE; - } - } - } - return result; -} - -VkBool32 CheckPreserved(const layer_data *my_data, const VkRenderPassCreateInfo *pCreateInfo, const int index, - const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, VkBool32 &skip_call) { - const DAGNode &node = subpass_to_node[index]; - // If this node writes to the attachment return true as next nodes need to preserve the attachment. - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index]; - for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { - if (attachment == subpass.pColorAttachments[j].attachment) - return VK_TRUE; - } - if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { - if (attachment == subpass.pDepthStencilAttachment->attachment) - return VK_TRUE; - } - VkBool32 result = VK_FALSE; - // Loop through previous nodes and see if any of them write to the attachment. - for (auto elem : node.prev) { - result |= CheckPreserved(my_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip_call); - } - // If the attachment was written to by a previous node than this node needs to preserve it. - if (result && depth > 0) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index]; - VkBool32 has_preserved = VK_FALSE; - for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) { - if (subpass.pPreserveAttachments[j] == attachment) { - has_preserved = VK_TRUE; - break; - } - } - if (has_preserved == VK_FALSE) { - skip_call |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_RENDERPASS, "DS", - "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index); - } - } - return result; -} - -template <class T> bool isRangeOverlapping(T offset1, T size1, T offset2, T size2) { - return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) || - ((offset1 > offset2) && (offset1 < (offset2 + size2))); -} - -bool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) { - return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) && - isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount)); -} - -VkBool32 ValidateDependencies(const layer_data *my_data, const VkRenderPassBeginInfo *pRenderPassBegin, - const std::vector<DAGNode> &subpass_to_node) { - VkBool32 skip_call = VK_FALSE; - const VkFramebufferCreateInfo *pFramebufferInfo = &my_data->frameBufferMap.at(pRenderPassBegin->framebuffer).createInfo; - const VkRenderPassCreateInfo *pCreateInfo = my_data->renderPassMap.at(pRenderPassBegin->renderPass)->pCreateInfo; - std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount); - std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount); - std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount); - // Find overlapping attachments - for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { - for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) { - VkImageView viewi = pFramebufferInfo->pAttachments[i]; - VkImageView viewj = pFramebufferInfo->pAttachments[j]; - if (viewi == viewj) { - overlapping_attachments[i].push_back(j); - overlapping_attachments[j].push_back(i); - continue; - } - auto view_data_i = my_data->imageViewMap.find(viewi); - auto view_data_j = my_data->imageViewMap.find(viewj); - if (view_data_i == my_data->imageViewMap.end() || view_data_j == my_data->imageViewMap.end()) { - continue; - } - if (view_data_i->second->image == view_data_j->second->image && - isRegionOverlapping(view_data_i->second->subresourceRange, view_data_j->second->subresourceRange)) { - overlapping_attachments[i].push_back(j); - overlapping_attachments[j].push_back(i); - continue; - } - auto image_data_i = my_data->imageMap.find(view_data_i->second->image); - auto image_data_j = my_data->imageMap.find(view_data_j->second->image); - if (image_data_i == my_data->imageMap.end() || image_data_j == my_data->imageMap.end()) { - continue; - } - if (image_data_i->second.mem == image_data_j->second.mem && - isRangeOverlapping(image_data_i->second.memOffset, image_data_i->second.memSize, image_data_j->second.memOffset, - image_data_j->second.memSize)) { - overlapping_attachments[i].push_back(j); - overlapping_attachments[j].push_back(i); - } - } - } - for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) { - uint32_t attachment = i; - for (auto other_attachment : overlapping_attachments[i]) { - if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) { - skip_call |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't " - "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.", - attachment, other_attachment); - } - if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) { - skip_call |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't " - "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.", - other_attachment, attachment); - } - } - } - // Find for each attachment the subpasses that use them. - for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; - for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { - uint32_t attachment = subpass.pInputAttachments[j].attachment; - input_attachment_to_subpass[attachment].push_back(i); - for (auto overlapping_attachment : overlapping_attachments[attachment]) { - input_attachment_to_subpass[overlapping_attachment].push_back(i); - } - } - for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { - uint32_t attachment = subpass.pColorAttachments[j].attachment; - output_attachment_to_subpass[attachment].push_back(i); - for (auto overlapping_attachment : overlapping_attachments[attachment]) { - output_attachment_to_subpass[overlapping_attachment].push_back(i); - } - } - if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { - uint32_t attachment = subpass.pDepthStencilAttachment->attachment; - output_attachment_to_subpass[attachment].push_back(i); - for (auto overlapping_attachment : overlapping_attachments[attachment]) { - output_attachment_to_subpass[overlapping_attachment].push_back(i); - } - } - } - // If there is a dependency needed make sure one exists - for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; - // If the attachment is an input then all subpasses that output must have a dependency relationship - for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { - const uint32_t &attachment = subpass.pInputAttachments[j].attachment; - CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call); - } - // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship - for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { - const uint32_t &attachment = subpass.pColorAttachments[j].attachment; - CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call); - CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call); - } - if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { - const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment; - CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call); - CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call); - } - } - // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was - // written. - for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; - for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { - CheckPreserved(my_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip_call); - } - } - return skip_call; -} - -VkBool32 ValidateLayouts(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo) { - VkBool32 skip = VK_FALSE; - - for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; - for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { - if (subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && - subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - if (subpass.pInputAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) { - // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance - skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, - (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", - "Layout for input attachment is GENERAL but should be READ_ONLY_OPTIMAL."); - } else { - skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", - "Layout for input attachment is %s but can only be READ_ONLY_OPTIMAL or GENERAL.", - string_VkImageLayout(subpass.pInputAttachments[j].layout)); - } - } - } - for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { - if (subpass.pColorAttachments[j].layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { - if (subpass.pColorAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) { - // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance - skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, - (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", - "Layout for color attachment is GENERAL but should be COLOR_ATTACHMENT_OPTIMAL."); - } else { - skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", - "Layout for color attachment is %s but can only be COLOR_ATTACHMENT_OPTIMAL or GENERAL.", - string_VkImageLayout(subpass.pColorAttachments[j].layout)); - } - } - } - if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) { - if (subpass.pDepthStencilAttachment->layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { - if (subpass.pDepthStencilAttachment->layout == VK_IMAGE_LAYOUT_GENERAL) { - // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance - skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, - (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", - "Layout for depth attachment is GENERAL but should be DEPTH_STENCIL_ATTACHMENT_OPTIMAL."); - } else { - skip |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", - "Layout for depth attachment is %s but can only be DEPTH_STENCIL_ATTACHMENT_OPTIMAL or GENERAL.", - string_VkImageLayout(subpass.pDepthStencilAttachment->layout)); - } - } - } - } - return skip; -} - -VkBool32 CreatePassDAG(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, - std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) { - VkBool32 skip_call = VK_FALSE; - for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - DAGNode &subpass_node = subpass_to_node[i]; - subpass_node.pass = i; - } - for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) { - const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i]; - if (dependency.srcSubpass > dependency.dstSubpass && dependency.srcSubpass != VK_SUBPASS_EXTERNAL && - dependency.dstSubpass != VK_SUBPASS_EXTERNAL) { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_RENDERPASS, "DS", - "Depedency graph must be specified such that an earlier pass cannot depend on a later pass."); - } else if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL && dependency.dstSubpass == VK_SUBPASS_EXTERNAL) { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external."); - } else if (dependency.srcSubpass == dependency.dstSubpass) { - has_self_dependency[dependency.srcSubpass] = true; - } - if (dependency.dstSubpass != VK_SUBPASS_EXTERNAL) { - subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass); - } - if (dependency.srcSubpass != VK_SUBPASS_EXTERNAL) { - subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass); - } - } - return skip_call; -} -// TODOSC : Add intercept of vkCreateShaderModule - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkShaderModule *pShaderModule) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkBool32 skip_call = VK_FALSE; - if (!shader_is_spirv(pCreateInfo)) { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - /* dev */ 0, __LINE__, SHADER_CHECKER_NON_SPIRV_SHADER, "SC", "Shader is not SPIR-V"); - } - - if (VK_FALSE != skip_call) - return VK_ERROR_VALIDATION_FAILED_EXT; - - VkResult res = my_data->device_dispatch_table->CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule); - - if (res == VK_SUCCESS) { - loader_platform_thread_lock_mutex(&globalLock); - my_data->shaderModuleMap[*pShaderModule] = new shader_module(pCreateInfo); - loader_platform_thread_unlock_mutex(&globalLock); - } - return res; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkRenderPass *pRenderPass) { - VkBool32 skip_call = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - // Create DAG - std::vector<bool> has_self_dependency(pCreateInfo->subpassCount); - std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount); - skip_call |= CreatePassDAG(dev_data, device, pCreateInfo, subpass_to_node, has_self_dependency); - // Validate - skip_call |= ValidateLayouts(dev_data, device, pCreateInfo); - if (VK_FALSE != skip_call) { - return VK_ERROR_VALIDATION_FAILED_EXT; - } - loader_platform_thread_unlock_mutex(&globalLock); - VkResult result = dev_data->device_dispatch_table->CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - // TODOSC : Merge in tracking of renderpass from shader_checker - // Shadow create info and store in map - VkRenderPassCreateInfo *localRPCI = new VkRenderPassCreateInfo(*pCreateInfo); - if (pCreateInfo->pAttachments) { - localRPCI->pAttachments = new VkAttachmentDescription[localRPCI->attachmentCount]; - memcpy((void *)localRPCI->pAttachments, pCreateInfo->pAttachments, - localRPCI->attachmentCount * sizeof(VkAttachmentDescription)); - } - if (pCreateInfo->pSubpasses) { - localRPCI->pSubpasses = new VkSubpassDescription[localRPCI->subpassCount]; - memcpy((void *)localRPCI->pSubpasses, pCreateInfo->pSubpasses, localRPCI->subpassCount * sizeof(VkSubpassDescription)); - - for (uint32_t i = 0; i < localRPCI->subpassCount; i++) { - VkSubpassDescription *subpass = (VkSubpassDescription *)&localRPCI->pSubpasses[i]; - const uint32_t attachmentCount = subpass->inputAttachmentCount + - subpass->colorAttachmentCount * (1 + (subpass->pResolveAttachments ? 1 : 0)) + - ((subpass->pDepthStencilAttachment) ? 1 : 0) + subpass->preserveAttachmentCount; - VkAttachmentReference *attachments = new VkAttachmentReference[attachmentCount]; - - memcpy(attachments, subpass->pInputAttachments, sizeof(attachments[0]) * subpass->inputAttachmentCount); - subpass->pInputAttachments = attachments; - attachments += subpass->inputAttachmentCount; - - memcpy(attachments, subpass->pColorAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount); - subpass->pColorAttachments = attachments; - attachments += subpass->colorAttachmentCount; - - if (subpass->pResolveAttachments) { - memcpy(attachments, subpass->pResolveAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount); - subpass->pResolveAttachments = attachments; - attachments += subpass->colorAttachmentCount; - } - - if (subpass->pDepthStencilAttachment) { - memcpy(attachments, subpass->pDepthStencilAttachment, sizeof(attachments[0]) * 1); - subpass->pDepthStencilAttachment = attachments; - attachments += 1; - } - - memcpy(attachments, subpass->pPreserveAttachments, sizeof(attachments[0]) * subpass->preserveAttachmentCount); - subpass->pPreserveAttachments = &attachments->attachment; - } - } - if (pCreateInfo->pDependencies) { - localRPCI->pDependencies = new VkSubpassDependency[localRPCI->dependencyCount]; - memcpy((void *)localRPCI->pDependencies, pCreateInfo->pDependencies, - localRPCI->dependencyCount * sizeof(VkSubpassDependency)); - } - dev_data->renderPassMap[*pRenderPass] = new RENDER_PASS_NODE(localRPCI); - dev_data->renderPassMap[*pRenderPass]->hasSelfDependency = has_self_dependency; - dev_data->renderPassMap[*pRenderPass]->subpassToNode = subpass_to_node; - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} -// Free the renderpass shadow -static void deleteRenderPasses(layer_data *my_data) { - if (my_data->renderPassMap.size() <= 0) - return; - for (auto ii = my_data->renderPassMap.begin(); ii != my_data->renderPassMap.end(); ++ii) { - const VkRenderPassCreateInfo *pRenderPassInfo = (*ii).second->pCreateInfo; - delete[] pRenderPassInfo->pAttachments; - if (pRenderPassInfo->pSubpasses) { - for (uint32_t i = 0; i < pRenderPassInfo->subpassCount; ++i) { - // Attachements are all allocated in a block, so just need to - // find the first non-null one to delete - if (pRenderPassInfo->pSubpasses[i].pInputAttachments) { - delete[] pRenderPassInfo->pSubpasses[i].pInputAttachments; - } else if (pRenderPassInfo->pSubpasses[i].pColorAttachments) { - delete[] pRenderPassInfo->pSubpasses[i].pColorAttachments; - } else if (pRenderPassInfo->pSubpasses[i].pResolveAttachments) { - delete[] pRenderPassInfo->pSubpasses[i].pResolveAttachments; - } else if (pRenderPassInfo->pSubpasses[i].pPreserveAttachments) { - delete[] pRenderPassInfo->pSubpasses[i].pPreserveAttachments; - } - } - delete[] pRenderPassInfo->pSubpasses; - } - delete[] pRenderPassInfo->pDependencies; - delete pRenderPassInfo; - delete (*ii).second; - } - my_data->renderPassMap.clear(); -} - -VkBool32 VerifyFramebufferAndRenderPassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin) { - VkBool32 skip_call = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); - const VkRenderPassCreateInfo *pRenderPassInfo = dev_data->renderPassMap[pRenderPassBegin->renderPass]->pCreateInfo; - const VkFramebufferCreateInfo framebufferInfo = dev_data->frameBufferMap[pRenderPassBegin->framebuffer].createInfo; - if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using a framebuffer " - "with a different number of attachments."); - } - for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) { - const VkImageView &image_view = framebufferInfo.pAttachments[i]; - auto image_data = dev_data->imageViewMap.find(image_view); - assert(image_data != dev_data->imageViewMap.end()); - const VkImage &image = image_data->second->image; - const VkImageSubresourceRange &subRange = image_data->second->subresourceRange; - IMAGE_CMD_BUF_LAYOUT_NODE newNode = {pRenderPassInfo->pAttachments[i].initialLayout, - pRenderPassInfo->pAttachments[i].initialLayout}; - // TODO: Do not iterate over every possibility - consolidate where possible - for (uint32_t j = 0; j < subRange.levelCount; j++) { - uint32_t level = subRange.baseMipLevel + j; - for (uint32_t k = 0; k < subRange.layerCount; k++) { - uint32_t layer = subRange.baseArrayLayer + k; - VkImageSubresource sub = {subRange.aspectMask, level, layer}; - IMAGE_CMD_BUF_LAYOUT_NODE node; - if (!FindLayout(pCB, image, sub, node)) { - SetLayout(pCB, image, sub, newNode); - continue; - } - if (newNode.layout != node.layout) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using attachment %i " - "where the " - "intial layout differs from the starting layout.", - i); - } - } - } - } - return skip_call; -} - -void TransitionSubpassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, const int subpass_index) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); - auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass); - if (render_pass_data == dev_data->renderPassMap.end()) { - return; - } - const VkRenderPassCreateInfo *pRenderPassInfo = render_pass_data->second->pCreateInfo; - auto framebuffer_data = dev_data->frameBufferMap.find(pRenderPassBegin->framebuffer); - if (framebuffer_data == dev_data->frameBufferMap.end()) { - return; - } - const VkFramebufferCreateInfo framebufferInfo = framebuffer_data->second.createInfo; - const VkSubpassDescription &subpass = pRenderPassInfo->pSubpasses[subpass_index]; - for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { - const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pInputAttachments[j].attachment]; - SetLayout(dev_data, pCB, image_view, subpass.pInputAttachments[j].layout); - } - for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { - const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pColorAttachments[j].attachment]; - SetLayout(dev_data, pCB, image_view, subpass.pColorAttachments[j].layout); - } - if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) { - const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pDepthStencilAttachment->attachment]; - SetLayout(dev_data, pCB, image_view, subpass.pDepthStencilAttachment->layout); - } -} - -VkBool32 validatePrimaryCommandBuffer(const layer_data *my_data, const GLOBAL_CB_NODE *pCB, const std::string &cmd_name) { - VkBool32 skip_call = VK_FALSE; - if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) { - skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", "Cannot execute command %s on a secondary command buffer.", - cmd_name.c_str()); - } - return skip_call; -} - -void TransitionFinalSubpassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer); - auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass); - if (render_pass_data == dev_data->renderPassMap.end()) { - return; - } - const VkRenderPassCreateInfo *pRenderPassInfo = render_pass_data->second->pCreateInfo; - auto framebuffer_data = dev_data->frameBufferMap.find(pRenderPassBegin->framebuffer); - if (framebuffer_data == dev_data->frameBufferMap.end()) { - return; - } - const VkFramebufferCreateInfo framebufferInfo = framebuffer_data->second.createInfo; - for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) { - const VkImageView &image_view = framebufferInfo.pAttachments[i]; - SetLayout(dev_data, pCB, image_view, pRenderPassInfo->pAttachments[i].finalLayout); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, VkSubpassContents contents) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - if (pRenderPassBegin && pRenderPassBegin->renderPass) { - skipCall |= VerifyFramebufferAndRenderPassLayouts(commandBuffer, pRenderPassBegin); - auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass); - if (render_pass_data != dev_data->renderPassMap.end()) { - skipCall |= ValidateDependencies(dev_data, pRenderPassBegin, render_pass_data->second->subpassToNode); - } - skipCall |= insideRenderPass(dev_data, pCB, "vkCmdBeginRenderPass"); - skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdBeginRenderPass"); - skipCall |= addCmd(dev_data, pCB, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()"); - pCB->activeRenderPass = pRenderPassBegin->renderPass; - // This is a shallow copy as that is all that is needed for now - pCB->activeRenderPassBeginInfo = *pRenderPassBegin; - pCB->activeSubpass = 0; - pCB->activeSubpassContents = contents; - pCB->framebuffer = pRenderPassBegin->framebuffer; - // Connect this framebuffer to this cmdBuffer - dev_data->frameBufferMap[pCB->framebuffer].referencingCmdBuffers.insert(pCB->commandBuffer); - } else { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot use a NULL RenderPass object in vkCmdBeginRenderPass()"); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - dev_data->device_dispatch_table->CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents); - loader_platform_thread_lock_mutex(&globalLock); - // This is a shallow copy as that is all that is needed for now - dev_data->renderPassBeginInfo = *pRenderPassBegin; - dev_data->currentSubpass = 0; - loader_platform_thread_unlock_mutex(&globalLock); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - TransitionSubpassLayouts(commandBuffer, &dev_data->renderPassBeginInfo, ++dev_data->currentSubpass); - if (pCB) { - skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass"); - skipCall |= addCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()"); - pCB->activeSubpass++; - pCB->activeSubpassContents = contents; - TransitionSubpassLayouts(commandBuffer, &pCB->activeRenderPassBeginInfo, pCB->activeSubpass); - if (pCB->lastBoundPipeline) { - skipCall |= validatePipelineState(dev_data, pCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pCB->lastBoundPipeline); - } - skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdNextSubpass(commandBuffer, contents); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass(VkCommandBuffer commandBuffer) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - TransitionFinalSubpassLayouts(commandBuffer, &dev_data->renderPassBeginInfo); - if (pCB) { - skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass"); - skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass"); - skipCall |= addCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()"); - TransitionFinalSubpassLayouts(commandBuffer, &pCB->activeRenderPassBeginInfo); - pCB->activeRenderPass = 0; - pCB->activeSubpass = 0; - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdEndRenderPass(commandBuffer); -} - -bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass, - VkRenderPass primaryPass, uint32_t primaryAttach, uint32_t secondaryAttach, const char *msg) { - return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", - "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a render pass %" PRIx64 - " that is not compatible with the current render pass %" PRIx64 "." - "Attachment %" PRIu32 " is not compatable with %" PRIu32 ". %s", - (void *)secondaryBuffer, (uint64_t)(secondaryPass), (uint64_t)(primaryPass), primaryAttach, secondaryAttach, - msg); -} - -bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass, - uint32_t primaryAttach, VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass, - uint32_t secondaryAttach, bool is_multi) { - bool skip_call = false; - auto primary_data = dev_data->renderPassMap.find(primaryPass); - auto secondary_data = dev_data->renderPassMap.find(secondaryPass); - if (primary_data->second->pCreateInfo->attachmentCount <= primaryAttach) { - primaryAttach = VK_ATTACHMENT_UNUSED; - } - if (secondary_data->second->pCreateInfo->attachmentCount <= secondaryAttach) { - secondaryAttach = VK_ATTACHMENT_UNUSED; - } - if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) { - return skip_call; - } - if (primaryAttach == VK_ATTACHMENT_UNUSED) { - skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, - secondaryAttach, "The first is unused while the second is not."); - return skip_call; - } - if (secondaryAttach == VK_ATTACHMENT_UNUSED) { - skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, - secondaryAttach, "The second is unused while the first is not."); - return skip_call; - } - if (primary_data->second->pCreateInfo->pAttachments[primaryAttach].format != - secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].format) { - skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, - secondaryAttach, "They have different formats."); - } - if (primary_data->second->pCreateInfo->pAttachments[primaryAttach].samples != - secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].samples) { - skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, - secondaryAttach, "They have different samples."); - } - if (is_multi && - primary_data->second->pCreateInfo->pAttachments[primaryAttach].flags != - secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].flags) { - skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach, - secondaryAttach, "They have different flags."); - } - return skip_call; -} - -bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass, - VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass, const int subpass, bool is_multi) { - bool skip_call = false; - auto primary_data = dev_data->renderPassMap.find(primaryPass); - auto secondary_data = dev_data->renderPassMap.find(secondaryPass); - const VkSubpassDescription &primary_desc = primary_data->second->pCreateInfo->pSubpasses[subpass]; - const VkSubpassDescription &secondary_desc = secondary_data->second->pCreateInfo->pSubpasses[subpass]; - uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount); - for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) { - uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED; - if (i < primary_desc.inputAttachmentCount) { - primary_input_attach = primary_desc.pInputAttachments[i].attachment; - } - if (i < secondary_desc.inputAttachmentCount) { - secondary_input_attach = secondary_desc.pInputAttachments[i].attachment; - } - skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_input_attach, secondaryBuffer, - secondaryPass, secondary_input_attach, is_multi); - } - uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount); - for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) { - uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED; - if (i < primary_desc.colorAttachmentCount) { - primary_color_attach = primary_desc.pColorAttachments[i].attachment; - } - if (i < secondary_desc.colorAttachmentCount) { - secondary_color_attach = secondary_desc.pColorAttachments[i].attachment; - } - skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_color_attach, secondaryBuffer, - secondaryPass, secondary_color_attach, is_multi); - uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED; - if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) { - primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment; - } - if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) { - secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment; - } - skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_resolve_attach, secondaryBuffer, - secondaryPass, secondary_resolve_attach, is_multi); - } - uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED; - if (primary_desc.pDepthStencilAttachment) { - primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment; - } - if (secondary_desc.pDepthStencilAttachment) { - secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment; - } - skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_depthstencil_attach, secondaryBuffer, - secondaryPass, secondary_depthstencil_attach, is_multi); - return skip_call; -} - -bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass, - VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass) { - bool skip_call = false; - // Early exit if renderPass objects are identical (and therefore compatible) - if (primaryPass == secondaryPass) - return skip_call; - auto primary_data = dev_data->renderPassMap.find(primaryPass); - auto secondary_data = dev_data->renderPassMap.find(secondaryPass); - if (primary_data == dev_data->renderPassMap.end() || primary_data->second == nullptr) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", - "vkCmdExecuteCommands() called w/ invalid current Cmd Buffer %p which has invalid render pass %" PRIx64 ".", - (void *)primaryBuffer, (uint64_t)(primaryPass)); - return skip_call; - } - if (secondary_data == dev_data->renderPassMap.end() || secondary_data->second == nullptr) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", - "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer %p which has invalid render pass %" PRIx64 ".", - (void *)secondaryBuffer, (uint64_t)(secondaryPass)); - return skip_call; - } - if (primary_data->second->pCreateInfo->subpassCount != secondary_data->second->pCreateInfo->subpassCount) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", - "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a render pass %" PRIx64 - " that is not compatible with the current render pass %" PRIx64 "." - "They have a different number of subpasses.", - (void *)secondaryBuffer, (uint64_t)(secondaryPass), (uint64_t)(primaryPass)); - return skip_call; - } - bool is_multi = primary_data->second->pCreateInfo->subpassCount > 1; - for (uint32_t i = 0; i < primary_data->second->pCreateInfo->subpassCount; ++i) { - skip_call |= - validateSubpassCompatibility(dev_data, primaryBuffer, primaryPass, secondaryBuffer, secondaryPass, i, is_multi); - } - return skip_call; -} - -bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB, - VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) { - bool skip_call = false; - if (!pSubCB->beginInfo.pInheritanceInfo) { - return skip_call; - } - VkFramebuffer primary_fb = pCB->framebuffer; - VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer; - if (secondary_fb != VK_NULL_HANDLE) { - if (primary_fb != secondary_fb) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", - "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a framebuffer %" PRIx64 - " that is not compatible with the current framebuffer %" PRIx64 ".", - (void *)secondaryBuffer, (uint64_t)(secondary_fb), (uint64_t)(primary_fb)); - } - auto fb_data = dev_data->frameBufferMap.find(secondary_fb); - if (fb_data == dev_data->frameBufferMap.end()) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p " - "which has invalid framebuffer %" PRIx64 ".", - (void *)secondaryBuffer, (uint64_t)(secondary_fb)); - return skip_call; - } - skip_call |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb_data->second.createInfo.renderPass, - secondaryBuffer, pSubCB->beginInfo.pInheritanceInfo->renderPass); - } - return skip_call; -} - -bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) { - bool skipCall = false; - unordered_set<int> activeTypes; - for (auto queryObject : pCB->activeQueries) { - auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool); - if (queryPoolData != dev_data->queryPoolMap.end()) { - if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS && - pSubCB->beginInfo.pInheritanceInfo) { - VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics; - if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) { - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", - "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p " - "which has invalid active query pool %" PRIx64 ". Pipeline statistics is being queried so the command " - "buffer must have all bits set on the queryPool.", - reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first)); - } - } - activeTypes.insert(queryPoolData->second.createInfo.queryType); - } - } - for (auto queryObject : pSubCB->startedQueries) { - auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool); - if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", - "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p " - "which has invalid active query pool %" PRIx64 "of type %d but a query of that type has been started on " - "secondary Cmd Buffer %p.", - reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first), - queryPoolData->second.createInfo.queryType, reinterpret_cast<void *>(pSubCB->commandBuffer)); - } - } - return skipCall; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount, const VkCommandBuffer *pCommandBuffers) { - VkBool32 skipCall = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer); - if (pCB) { - GLOBAL_CB_NODE *pSubCB = NULL; - for (uint32_t i = 0; i < commandBuffersCount; i++) { - pSubCB = getCBNode(dev_data, pCommandBuffers[i]); - if (!pSubCB) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, - DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", - "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p in element %u of pCommandBuffers array.", - (void *)pCommandBuffers[i], i); - } else if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) { - skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", - "vkCmdExecuteCommands() called w/ Primary Cmd Buffer %p in element %u of pCommandBuffers " - "array. All cmd buffers in pCommandBuffers array must be secondary.", - (void *)pCommandBuffers[i], i); - } else if (pCB->activeRenderPass) { // Secondary CB w/i RenderPass must have *CONTINUE_BIT set - if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) { - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS", - "vkCmdExecuteCommands(): Secondary Command Buffer (%p) executed within render pass (%#" PRIxLEAST64 - ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set.", - (void *)pCommandBuffers[i], (uint64_t)pCB->activeRenderPass); - } else { - // Make sure render pass is compatible with parent command buffer pass if has continue - skipCall |= validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass, pCommandBuffers[i], - pSubCB->beginInfo.pInheritanceInfo->renderPass); - skipCall |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB); - } - string errorString = ""; - if (!verify_renderpass_compatibility(dev_data, pCB->activeRenderPass, - pSubCB->beginInfo.pInheritanceInfo->renderPass, errorString)) { - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS", - "vkCmdExecuteCommands(): Secondary Command Buffer (%p) w/ render pass (%#" PRIxLEAST64 - ") is incompatible w/ primary command buffer (%p) w/ render pass (%#" PRIxLEAST64 ") due to: %s", - (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->renderPass, (void *)commandBuffer, - (uint64_t)pCB->activeRenderPass, errorString.c_str()); - } - // If framebuffer for secondary CB is not NULL, then it must match FB from vkCmdBeginRenderPass() - // that this CB will be executed in AND framebuffer must have been created w/ RP compatible w/ renderpass - if (pSubCB->beginInfo.pInheritanceInfo->framebuffer) { - if (pSubCB->beginInfo.pInheritanceInfo->framebuffer != pCB->activeRenderPassBeginInfo.framebuffer) { - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_FRAMEBUFFER_INCOMPATIBLE, "DS", - "vkCmdExecuteCommands(): Secondary Command Buffer (%p) references framebuffer (%#" PRIxLEAST64 - ") that does not match framebuffer (%#" PRIxLEAST64 ") in active renderpass (%#" PRIxLEAST64 ").", - (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->framebuffer, - (uint64_t)pCB->activeRenderPassBeginInfo.framebuffer, (uint64_t)pCB->activeRenderPass); - } - } - } - // TODO(mlentine): Move more logic into this method - skipCall |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB); - skipCall |= validateCommandBufferState(dev_data, pSubCB); - // Secondary cmdBuffers are considered pending execution starting w/ - // being recorded - if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) { - if (dev_data->globalInFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->globalInFlightCmdBuffers.end()) { - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS", - "Attempt to simultaneously execute CB %#" PRIxLEAST64 " w/o VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT " - "set!", - (uint64_t)(pCB->commandBuffer)); - } - if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) { - // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous - skipCall |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS", - "vkCmdExecuteCommands(): Secondary Command Buffer (%#" PRIxLEAST64 - ") does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer " - "(%#" PRIxLEAST64 ") to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT " - "set, even though it does.", - (uint64_t)(pCommandBuffers[i]), (uint64_t)(pCB->commandBuffer)); - pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - } - } - if (!pCB->activeQueries.empty() && !dev_data->physDevProperties.features.inheritedQueries) { - skipCall |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", - "vkCmdExecuteCommands(): Secondary Command Buffer " - "(%#" PRIxLEAST64 ") cannot be submitted with a query in " - "flight and inherited queries not " - "supported on this device.", - reinterpret_cast<uint64_t>(pCommandBuffers[i])); - } - pSubCB->primaryCommandBuffer = pCB->commandBuffer; - pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer); - dev_data->globalInFlightCmdBuffers.insert(pSubCB->commandBuffer); - } - skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteComands"); - skipCall |= addCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteComands()"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) - dev_data->device_dispatch_table->CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers); -} - -VkBool32 ValidateMapImageLayouts(VkDevice device, VkDeviceMemory mem) { - VkBool32 skip_call = VK_FALSE; - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - auto mem_data = dev_data->memImageMap.find(mem); - if (mem_data != dev_data->memImageMap.end()) { - std::vector<VkImageLayout> layouts; - if (FindLayouts(dev_data, mem_data->second, layouts)) { - for (auto layout : layouts) { - if (layout != VK_IMAGE_LAYOUT_PREINITIALIZED && layout != VK_IMAGE_LAYOUT_GENERAL) { - skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, - __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot map an image with layout %s. Only " - "GENERAL or PREINITIALIZED are supported.", - string_VkImageLayout(layout)); - } - } - } - } - return skip_call; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags, void **ppData) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - - VkBool32 skip_call = VK_FALSE; - loader_platform_thread_lock_mutex(&globalLock); - skip_call = ValidateMapImageLayouts(device, mem); - loader_platform_thread_unlock_mutex(&globalLock); - - if (VK_FALSE == skip_call) { - return dev_data->device_dispatch_table->MapMemory(device, mem, offset, size, flags, ppData); - } - return VK_ERROR_VALIDATION_FAILED_EXT; -} - -VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->BindImageMemory(device, image, mem, memOffset); - VkMemoryRequirements memRequirements; - dev_data->device_dispatch_table->GetImageMemoryRequirements(device, image, &memRequirements); - loader_platform_thread_lock_mutex(&globalLock); - dev_data->memImageMap[mem] = image; - dev_data->imageMap[image].mem = mem; - dev_data->imageMap[image].memOffset = memOffset; - dev_data->imageMap[image].memSize = memRequirements.size; - loader_platform_thread_unlock_mutex(&globalLock); - return result; -} - -VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent(VkDevice device, VkEvent event) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - dev_data->eventMap[event].needsSignaled = false; - dev_data->eventMap[event].stageMask = VK_PIPELINE_STAGE_HOST_BIT; - loader_platform_thread_unlock_mutex(&globalLock); - VkResult result = dev_data->device_dispatch_table->SetEvent(device, event); - return result; -} - -VKAPI_ATTR VkResult VKAPI_CALL -vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); - VkBool32 skip_call = VK_FALSE; - - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) { - const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx]; - for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) { - if (dev_data->semaphoreMap[bindInfo.pWaitSemaphores[i]].signaled) { - dev_data->semaphoreMap[bindInfo.pWaitSemaphores[i]].signaled = 0; - } else { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, - __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS", - "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.", - (uint64_t)(queue), (uint64_t)(bindInfo.pWaitSemaphores[i])); - } - } - for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) { - dev_data->semaphoreMap[bindInfo.pSignalSemaphores[i]].signaled = 1; - } - } - loader_platform_thread_unlock_mutex(&globalLock); - - if (VK_FALSE == skip_call) - return dev_data->device_dispatch_table->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence); - else - return VK_ERROR_VALIDATION_FAILED_EXT; -} - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore); - if (result == VK_SUCCESS) { - loader_platform_thread_lock_mutex(&globalLock); - dev_data->semaphoreMap[*pSemaphore].signaled = 0; - dev_data->semaphoreMap[*pSemaphore].in_use.store(0); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VKAPI_ATTR VkResult VKAPI_CALL -vkCreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreateEvent(device, pCreateInfo, pAllocator, pEvent); - if (result == VK_SUCCESS) { - loader_platform_thread_lock_mutex(&globalLock); - dev_data->eventMap[*pEvent].needsSignaled = false; - dev_data->eventMap[*pEvent].in_use.store(0); - dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkSwapchainKHR *pSwapchain) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); - - if (VK_SUCCESS == result) { - SWAPCHAIN_NODE *swapchain_data = new SWAPCHAIN_NODE(pCreateInfo); - loader_platform_thread_lock_mutex(&globalLock); - dev_data->device_extensions.swapchainMap[*pSwapchain] = swapchain_data; - loader_platform_thread_unlock_mutex(&globalLock); - } - - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - - loader_platform_thread_lock_mutex(&globalLock); - auto swapchain_data = dev_data->device_extensions.swapchainMap.find(swapchain); - if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) { - if (swapchain_data->second->images.size() > 0) { - for (auto swapchain_image : swapchain_data->second->images) { - auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image); - if (image_sub != dev_data->imageSubresourceMap.end()) { - for (auto imgsubpair : image_sub->second) { - auto image_item = dev_data->imageLayoutMap.find(imgsubpair); - if (image_item != dev_data->imageLayoutMap.end()) { - dev_data->imageLayoutMap.erase(image_item); - } - } - dev_data->imageSubresourceMap.erase(image_sub); - } - } - } - delete swapchain_data->second; - dev_data->device_extensions.swapchainMap.erase(swapchain); - } - loader_platform_thread_unlock_mutex(&globalLock); - dev_data->device_dispatch_table->DestroySwapchainKHR(device, swapchain, pAllocator); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount, VkImage *pSwapchainImages) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = dev_data->device_dispatch_table->GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages); - - if (result == VK_SUCCESS && pSwapchainImages != NULL) { - // This should never happen and is checked by param checker. - if (!pCount) - return result; - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < *pCount; ++i) { - IMAGE_LAYOUT_NODE image_layout_node; - image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED; - auto swapchain_node = dev_data->device_extensions.swapchainMap[swapchain]; - image_layout_node.format = swapchain_node->createInfo.imageFormat; - dev_data->imageMap[pSwapchainImages[i]].createInfo.mipLevels = 1; - dev_data->imageMap[pSwapchainImages[i]].createInfo.arrayLayers = swapchain_node->createInfo.imageArrayLayers; - swapchain_node->images.push_back(pSwapchainImages[i]); - ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()}; - dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair); - dev_data->imageLayoutMap[subpair] = image_layout_node; - dev_data->device_extensions.imageToSwapchainMap[pSwapchainImages[i]] = swapchain; - } - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); - VkBool32 skip_call = VK_FALSE; - - if (pPresentInfo) { - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) { - if (dev_data->semaphoreMap[pPresentInfo->pWaitSemaphores[i]].signaled) { - dev_data->semaphoreMap[pPresentInfo->pWaitSemaphores[i]].signaled = 0; - } else { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, - __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS", - "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.", - (uint64_t)(queue), (uint64_t)(pPresentInfo->pWaitSemaphores[i])); - } - } - for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) { - auto swapchain_data = dev_data->device_extensions.swapchainMap.find(pPresentInfo->pSwapchains[i]); - if (swapchain_data != dev_data->device_extensions.swapchainMap.end() && - pPresentInfo->pImageIndices[i] < swapchain_data->second->images.size()) { - VkImage image = swapchain_data->second->images[pPresentInfo->pImageIndices[i]]; - vector<VkImageLayout> layouts; - if (FindLayouts(dev_data, image, layouts)) { - for (auto layout : layouts) { - if (layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { - skip_call |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, - reinterpret_cast<uint64_t &>(queue), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", - "Images passed to present must be in layout " - "PRESENT_SOURCE_KHR but is in %s", - string_VkImageLayout(layout)); - } - } - } - } - } - loader_platform_thread_unlock_mutex(&globalLock); - } - - if (VK_FALSE == skip_call) - return dev_data->device_dispatch_table->QueuePresentKHR(queue, pPresentInfo); - return VK_ERROR_VALIDATION_FAILED_EXT; -} - -VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, - VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) { - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = - dev_data->device_dispatch_table->AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex); - loader_platform_thread_lock_mutex(&globalLock); - // FIXME/TODO: Need to add some thing code the "fence" parameter - dev_data->semaphoreMap[semaphore].signaled = 1; - loader_platform_thread_unlock_mutex(&globalLock); - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); - VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; - VkResult res = pTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback); - if (VK_SUCCESS == res) { - loader_platform_thread_lock_mutex(&globalLock); - res = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pMsgCallback); - loader_platform_thread_unlock_mutex(&globalLock); - } - return res; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, - VkDebugReportCallbackEXT msgCallback, - const VkAllocationCallbacks *pAllocator) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); - VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; - pTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator); - loader_platform_thread_lock_mutex(&globalLock); - layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator); - loader_platform_thread_unlock_mutex(&globalLock); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object, - size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); - my_data->instance_dispatch_table->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, - pMsg); -} - -VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) { - if (!strcmp(funcName, "vkGetDeviceProcAddr")) - return (PFN_vkVoidFunction)vkGetDeviceProcAddr; - if (!strcmp(funcName, "vkDestroyDevice")) - return (PFN_vkVoidFunction)vkDestroyDevice; - if (!strcmp(funcName, "vkQueueSubmit")) - return (PFN_vkVoidFunction)vkQueueSubmit; - if (!strcmp(funcName, "vkWaitForFences")) - return (PFN_vkVoidFunction)vkWaitForFences; - if (!strcmp(funcName, "vkGetFenceStatus")) - return (PFN_vkVoidFunction)vkGetFenceStatus; - if (!strcmp(funcName, "vkQueueWaitIdle")) - return (PFN_vkVoidFunction)vkQueueWaitIdle; - if (!strcmp(funcName, "vkDeviceWaitIdle")) - return (PFN_vkVoidFunction)vkDeviceWaitIdle; - if (!strcmp(funcName, "vkGetDeviceQueue")) - return (PFN_vkVoidFunction)vkGetDeviceQueue; - if (!strcmp(funcName, "vkDestroyInstance")) - return (PFN_vkVoidFunction)vkDestroyInstance; - if (!strcmp(funcName, "vkDestroyDevice")) - return (PFN_vkVoidFunction)vkDestroyDevice; - if (!strcmp(funcName, "vkDestroyFence")) - return (PFN_vkVoidFunction)vkDestroyFence; - if (!strcmp(funcName, "vkResetFences")) - return (PFN_vkVoidFunction)vkResetFences; - if (!strcmp(funcName, "vkDestroySemaphore")) - return (PFN_vkVoidFunction)vkDestroySemaphore; - if (!strcmp(funcName, "vkDestroyEvent")) - return (PFN_vkVoidFunction)vkDestroyEvent; - if (!strcmp(funcName, "vkDestroyQueryPool")) - return (PFN_vkVoidFunction)vkDestroyQueryPool; - if (!strcmp(funcName, "vkDestroyBuffer")) - return (PFN_vkVoidFunction)vkDestroyBuffer; - if (!strcmp(funcName, "vkDestroyBufferView")) - return (PFN_vkVoidFunction)vkDestroyBufferView; - if (!strcmp(funcName, "vkDestroyImage")) - return (PFN_vkVoidFunction)vkDestroyImage; - if (!strcmp(funcName, "vkDestroyImageView")) - return (PFN_vkVoidFunction)vkDestroyImageView; - if (!strcmp(funcName, "vkDestroyShaderModule")) - return (PFN_vkVoidFunction)vkDestroyShaderModule; - if (!strcmp(funcName, "vkDestroyPipeline")) - return (PFN_vkVoidFunction)vkDestroyPipeline; - if (!strcmp(funcName, "vkDestroyPipelineLayout")) - return (PFN_vkVoidFunction)vkDestroyPipelineLayout; - if (!strcmp(funcName, "vkDestroySampler")) - return (PFN_vkVoidFunction)vkDestroySampler; - if (!strcmp(funcName, "vkDestroyDescriptorSetLayout")) - return (PFN_vkVoidFunction)vkDestroyDescriptorSetLayout; - if (!strcmp(funcName, "vkDestroyDescriptorPool")) - return (PFN_vkVoidFunction)vkDestroyDescriptorPool; - if (!strcmp(funcName, "vkDestroyFramebuffer")) - return (PFN_vkVoidFunction)vkDestroyFramebuffer; - if (!strcmp(funcName, "vkDestroyRenderPass")) - return (PFN_vkVoidFunction)vkDestroyRenderPass; - if (!strcmp(funcName, "vkCreateBuffer")) - return (PFN_vkVoidFunction)vkCreateBuffer; - if (!strcmp(funcName, "vkCreateBufferView")) - return (PFN_vkVoidFunction)vkCreateBufferView; - if (!strcmp(funcName, "vkCreateImage")) - return (PFN_vkVoidFunction)vkCreateImage; - if (!strcmp(funcName, "vkCreateImageView")) - return (PFN_vkVoidFunction)vkCreateImageView; - if (!strcmp(funcName, "vkCreateFence")) - return (PFN_vkVoidFunction)vkCreateFence; - if (!strcmp(funcName, "CreatePipelineCache")) - return (PFN_vkVoidFunction)vkCreatePipelineCache; - if (!strcmp(funcName, "DestroyPipelineCache")) - return (PFN_vkVoidFunction)vkDestroyPipelineCache; - if (!strcmp(funcName, "GetPipelineCacheData")) - return (PFN_vkVoidFunction)vkGetPipelineCacheData; - if (!strcmp(funcName, "MergePipelineCaches")) - return (PFN_vkVoidFunction)vkMergePipelineCaches; - if (!strcmp(funcName, "vkCreateGraphicsPipelines")) - return (PFN_vkVoidFunction)vkCreateGraphicsPipelines; - if (!strcmp(funcName, "vkCreateComputePipelines")) - return (PFN_vkVoidFunction)vkCreateComputePipelines; - if (!strcmp(funcName, "vkCreateSampler")) - return (PFN_vkVoidFunction)vkCreateSampler; - if (!strcmp(funcName, "vkCreateDescriptorSetLayout")) - return (PFN_vkVoidFunction)vkCreateDescriptorSetLayout; - if (!strcmp(funcName, "vkCreatePipelineLayout")) - return (PFN_vkVoidFunction)vkCreatePipelineLayout; - if (!strcmp(funcName, "vkCreateDescriptorPool")) - return (PFN_vkVoidFunction)vkCreateDescriptorPool; - if (!strcmp(funcName, "vkResetDescriptorPool")) - return (PFN_vkVoidFunction)vkResetDescriptorPool; - if (!strcmp(funcName, "vkAllocateDescriptorSets")) - return (PFN_vkVoidFunction)vkAllocateDescriptorSets; - if (!strcmp(funcName, "vkFreeDescriptorSets")) - return (PFN_vkVoidFunction)vkFreeDescriptorSets; - if (!strcmp(funcName, "vkUpdateDescriptorSets")) - return (PFN_vkVoidFunction)vkUpdateDescriptorSets; - if (!strcmp(funcName, "vkCreateCommandPool")) - return (PFN_vkVoidFunction)vkCreateCommandPool; - if (!strcmp(funcName, "vkDestroyCommandPool")) - return (PFN_vkVoidFunction)vkDestroyCommandPool; - if (!strcmp(funcName, "vkResetCommandPool")) - return (PFN_vkVoidFunction)vkResetCommandPool; - if (!strcmp(funcName, "vkCreateQueryPool")) - return (PFN_vkVoidFunction)vkCreateQueryPool; - if (!strcmp(funcName, "vkAllocateCommandBuffers")) - return (PFN_vkVoidFunction)vkAllocateCommandBuffers; - if (!strcmp(funcName, "vkFreeCommandBuffers")) - return (PFN_vkVoidFunction)vkFreeCommandBuffers; - if (!strcmp(funcName, "vkBeginCommandBuffer")) - return (PFN_vkVoidFunction)vkBeginCommandBuffer; - if (!strcmp(funcName, "vkEndCommandBuffer")) - return (PFN_vkVoidFunction)vkEndCommandBuffer; - if (!strcmp(funcName, "vkResetCommandBuffer")) - return (PFN_vkVoidFunction)vkResetCommandBuffer; - if (!strcmp(funcName, "vkCmdBindPipeline")) - return (PFN_vkVoidFunction)vkCmdBindPipeline; - if (!strcmp(funcName, "vkCmdSetViewport")) - return (PFN_vkVoidFunction)vkCmdSetViewport; - if (!strcmp(funcName, "vkCmdSetScissor")) - return (PFN_vkVoidFunction)vkCmdSetScissor; - if (!strcmp(funcName, "vkCmdSetLineWidth")) - return (PFN_vkVoidFunction)vkCmdSetLineWidth; - if (!strcmp(funcName, "vkCmdSetDepthBias")) - return (PFN_vkVoidFunction)vkCmdSetDepthBias; - if (!strcmp(funcName, "vkCmdSetBlendConstants")) - return (PFN_vkVoidFunction)vkCmdSetBlendConstants; - if (!strcmp(funcName, "vkCmdSetDepthBounds")) - return (PFN_vkVoidFunction)vkCmdSetDepthBounds; - if (!strcmp(funcName, "vkCmdSetStencilCompareMask")) - return (PFN_vkVoidFunction)vkCmdSetStencilCompareMask; - if (!strcmp(funcName, "vkCmdSetStencilWriteMask")) - return (PFN_vkVoidFunction)vkCmdSetStencilWriteMask; - if (!strcmp(funcName, "vkCmdSetStencilReference")) - return (PFN_vkVoidFunction)vkCmdSetStencilReference; - if (!strcmp(funcName, "vkCmdBindDescriptorSets")) - return (PFN_vkVoidFunction)vkCmdBindDescriptorSets; - if (!strcmp(funcName, "vkCmdBindVertexBuffers")) - return (PFN_vkVoidFunction)vkCmdBindVertexBuffers; - if (!strcmp(funcName, "vkCmdBindIndexBuffer")) - return (PFN_vkVoidFunction)vkCmdBindIndexBuffer; - if (!strcmp(funcName, "vkCmdDraw")) - return (PFN_vkVoidFunction)vkCmdDraw; - if (!strcmp(funcName, "vkCmdDrawIndexed")) - return (PFN_vkVoidFunction)vkCmdDrawIndexed; - if (!strcmp(funcName, "vkCmdDrawIndirect")) - return (PFN_vkVoidFunction)vkCmdDrawIndirect; - if (!strcmp(funcName, "vkCmdDrawIndexedIndirect")) - return (PFN_vkVoidFunction)vkCmdDrawIndexedIndirect; - if (!strcmp(funcName, "vkCmdDispatch")) - return (PFN_vkVoidFunction)vkCmdDispatch; - if (!strcmp(funcName, "vkCmdDispatchIndirect")) - return (PFN_vkVoidFunction)vkCmdDispatchIndirect; - if (!strcmp(funcName, "vkCmdCopyBuffer")) - return (PFN_vkVoidFunction)vkCmdCopyBuffer; - if (!strcmp(funcName, "vkCmdCopyImage")) - return (PFN_vkVoidFunction)vkCmdCopyImage; - if (!strcmp(funcName, "vkCmdCopyBufferToImage")) - return (PFN_vkVoidFunction)vkCmdCopyBufferToImage; - if (!strcmp(funcName, "vkCmdCopyImageToBuffer")) - return (PFN_vkVoidFunction)vkCmdCopyImageToBuffer; - if (!strcmp(funcName, "vkCmdUpdateBuffer")) - return (PFN_vkVoidFunction)vkCmdUpdateBuffer; - if (!strcmp(funcName, "vkCmdFillBuffer")) - return (PFN_vkVoidFunction)vkCmdFillBuffer; - if (!strcmp(funcName, "vkCmdClearColorImage")) - return (PFN_vkVoidFunction)vkCmdClearColorImage; - if (!strcmp(funcName, "vkCmdClearDepthStencilImage")) - return (PFN_vkVoidFunction)vkCmdClearDepthStencilImage; - if (!strcmp(funcName, "vkCmdClearAttachments")) - return (PFN_vkVoidFunction)vkCmdClearAttachments; - if (!strcmp(funcName, "vkCmdResolveImage")) - return (PFN_vkVoidFunction)vkCmdResolveImage; - if (!strcmp(funcName, "vkCmdSetEvent")) - return (PFN_vkVoidFunction)vkCmdSetEvent; - if (!strcmp(funcName, "vkCmdResetEvent")) - return (PFN_vkVoidFunction)vkCmdResetEvent; - if (!strcmp(funcName, "vkCmdWaitEvents")) - return (PFN_vkVoidFunction)vkCmdWaitEvents; - if (!strcmp(funcName, "vkCmdPipelineBarrier")) - return (PFN_vkVoidFunction)vkCmdPipelineBarrier; - if (!strcmp(funcName, "vkCmdBeginQuery")) - return (PFN_vkVoidFunction)vkCmdBeginQuery; - if (!strcmp(funcName, "vkCmdEndQuery")) - return (PFN_vkVoidFunction)vkCmdEndQuery; - if (!strcmp(funcName, "vkCmdResetQueryPool")) - return (PFN_vkVoidFunction)vkCmdResetQueryPool; - if (!strcmp(funcName, "vkCmdPushConstants")) - return (PFN_vkVoidFunction)vkCmdPushConstants; - if (!strcmp(funcName, "vkCmdWriteTimestamp")) - return (PFN_vkVoidFunction)vkCmdWriteTimestamp; - if (!strcmp(funcName, "vkCreateFramebuffer")) - return (PFN_vkVoidFunction)vkCreateFramebuffer; - if (!strcmp(funcName, "vkCreateShaderModule")) - return (PFN_vkVoidFunction)vkCreateShaderModule; - if (!strcmp(funcName, "vkCreateRenderPass")) - return (PFN_vkVoidFunction)vkCreateRenderPass; - if (!strcmp(funcName, "vkCmdBeginRenderPass")) - return (PFN_vkVoidFunction)vkCmdBeginRenderPass; - if (!strcmp(funcName, "vkCmdNextSubpass")) - return (PFN_vkVoidFunction)vkCmdNextSubpass; - if (!strcmp(funcName, "vkCmdEndRenderPass")) - return (PFN_vkVoidFunction)vkCmdEndRenderPass; - if (!strcmp(funcName, "vkCmdExecuteCommands")) - return (PFN_vkVoidFunction)vkCmdExecuteCommands; - if (!strcmp(funcName, "vkSetEvent")) - return (PFN_vkVoidFunction)vkSetEvent; - if (!strcmp(funcName, "vkMapMemory")) - return (PFN_vkVoidFunction)vkMapMemory; - if (!strcmp(funcName, "vkGetQueryPoolResults")) - return (PFN_vkVoidFunction)vkGetQueryPoolResults; - if (!strcmp(funcName, "vkBindImageMemory")) - return (PFN_vkVoidFunction)vkBindImageMemory; - if (!strcmp(funcName, "vkQueueBindSparse")) - return (PFN_vkVoidFunction)vkQueueBindSparse; - if (!strcmp(funcName, "vkCreateSemaphore")) - return (PFN_vkVoidFunction)vkCreateSemaphore; - if (!strcmp(funcName, "vkCreateEvent")) - return (PFN_vkVoidFunction)vkCreateEvent; - - if (dev == NULL) - return NULL; - - layer_data *dev_data; - dev_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map); - - if (dev_data->device_extensions.wsi_enabled) { - if (!strcmp(funcName, "vkCreateSwapchainKHR")) - return (PFN_vkVoidFunction)vkCreateSwapchainKHR; - if (!strcmp(funcName, "vkDestroySwapchainKHR")) - return (PFN_vkVoidFunction)vkDestroySwapchainKHR; - if (!strcmp(funcName, "vkGetSwapchainImagesKHR")) - return (PFN_vkVoidFunction)vkGetSwapchainImagesKHR; - if (!strcmp(funcName, "vkAcquireNextImageKHR")) - return (PFN_vkVoidFunction)vkAcquireNextImageKHR; - if (!strcmp(funcName, "vkQueuePresentKHR")) - return (PFN_vkVoidFunction)vkQueuePresentKHR; - } - - VkLayerDispatchTable *pTable = dev_data->device_dispatch_table; - { - if (pTable->GetDeviceProcAddr == NULL) - return NULL; - return pTable->GetDeviceProcAddr(dev, funcName); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) { - if (!strcmp(funcName, "vkGetInstanceProcAddr")) - return (PFN_vkVoidFunction)vkGetInstanceProcAddr; - if (!strcmp(funcName, "vkGetDeviceProcAddr")) - return (PFN_vkVoidFunction)vkGetDeviceProcAddr; - if (!strcmp(funcName, "vkCreateInstance")) - return (PFN_vkVoidFunction)vkCreateInstance; - if (!strcmp(funcName, "vkCreateDevice")) - return (PFN_vkVoidFunction)vkCreateDevice; - if (!strcmp(funcName, "vkDestroyInstance")) - return (PFN_vkVoidFunction)vkDestroyInstance; - if (!strcmp(funcName, "vkEnumerateInstanceLayerProperties")) - return (PFN_vkVoidFunction)vkEnumerateInstanceLayerProperties; - if (!strcmp(funcName, "vkEnumerateInstanceExtensionProperties")) - return (PFN_vkVoidFunction)vkEnumerateInstanceExtensionProperties; - if (!strcmp(funcName, "vkEnumerateDeviceLayerProperties")) - return (PFN_vkVoidFunction)vkEnumerateDeviceLayerProperties; - if (!strcmp(funcName, "vkEnumerateDeviceExtensionProperties")) - return (PFN_vkVoidFunction)vkEnumerateDeviceExtensionProperties; - - if (instance == NULL) - return NULL; - - PFN_vkVoidFunction fptr; - - layer_data *my_data; - my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); - fptr = debug_report_get_instance_proc_addr(my_data->report_data, funcName); - if (fptr) - return fptr; - - VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; - if (pTable->GetInstanceProcAddr == NULL) - return NULL; - return pTable->GetInstanceProcAddr(instance, funcName); -} diff --git a/layers/draw_state.h b/layers/draw_state.h deleted file mode 100644 index aa76a23a..00000000 --- a/layers/draw_state.h +++ /dev/null @@ -1,703 +0,0 @@ -/* Copyright (c) 2015-2016 The Khronos Group Inc. - * Copyright (c) 2015-2016 Valve Corporation - * Copyright (c) 2015-2016 LunarG, Inc. - * Copyright (C) 2015-2016 Google Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and/or associated documentation files (the "Materials"), to - * deal in the Materials without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Materials, and to permit persons to whom the Materials - * are furnished to do so, subject to the following conditions: - * - * The above copyright notice(s) and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE - * USE OR OTHER DEALINGS IN THE MATERIALS - * - * Author: Courtney Goeltzenleuchter <courtneygo@google.com> - * Author: Tobin Ehlis <tobine@google.com> - * Author: Chris Forbes <chrisf@ijw.co.nz> - * Author: Mark Lobodzinski <mark@lunarg.com> - */ - -#include "vulkan/vk_layer.h" -#include <atomic> -#include <vector> -#include <memory> - -using std::vector; - -// Draw State ERROR codes -typedef enum _DRAW_STATE_ERROR { - DRAWSTATE_NONE, // Used for INFO & other non-error messages - DRAWSTATE_INTERNAL_ERROR, // Error with DrawState internal data structures - DRAWSTATE_NO_PIPELINE_BOUND, // Unable to identify a bound pipeline - DRAWSTATE_INVALID_POOL, // Invalid DS pool - DRAWSTATE_INVALID_SET, // Invalid DS - DRAWSTATE_INVALID_LAYOUT, // Invalid DS layout - DRAWSTATE_INVALID_IMAGE_LAYOUT, // Invalid Image layout - DRAWSTATE_INVALID_PIPELINE, // Invalid Pipeline handle referenced - DRAWSTATE_INVALID_PIPELINE_LAYOUT, // Invalid PipelineLayout - DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, // Attempt to create a pipeline - // with invalid state - DRAWSTATE_INVALID_COMMAND_BUFFER, // Invalid CommandBuffer referenced - DRAWSTATE_INVALID_BARRIER, // Invalid Barrier - DRAWSTATE_INVALID_BUFFER, // Invalid Buffer - DRAWSTATE_INVALID_QUERY, // Invalid Query - DRAWSTATE_INVALID_FENCE, // Invalid Fence - DRAWSTATE_INVALID_SEMAPHORE, // Invalid Semaphore - DRAWSTATE_INVALID_EVENT, // Invalid Event - DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, // binding in vkCmdBindVertexData() too - // large for PSO's - // pVertexBindingDescriptions array - DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, // binding offset in - // vkCmdBindIndexBuffer() out of - // alignment based on indexType - // DRAWSTATE_MISSING_DOT_PROGRAM, // No "dot" program in order - // to generate png image - DRAWSTATE_OUT_OF_MEMORY, // malloc failed - DRAWSTATE_INVALID_DESCRIPTOR_SET, // Descriptor Set handle is unknown - DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, // Type in layout vs. update are not the - // same - DRAWSTATE_DESCRIPTOR_STAGEFLAGS_MISMATCH, // StageFlags in layout are not - // the same throughout a single - // VkWriteDescriptorSet update - DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, // Descriptors set for update out - // of bounds for corresponding - // layout section - DRAWSTATE_DESCRIPTOR_POOL_EMPTY, // Attempt to allocate descriptor from a - // pool with no more descriptors of that - // type available - DRAWSTATE_CANT_FREE_FROM_NON_FREE_POOL, // Invalid to call - // vkFreeDescriptorSets on Sets - // allocated from a NON_FREE Pool - DRAWSTATE_INVALID_UPDATE_INDEX, // Index of requested update is invalid for - // specified descriptors set - DRAWSTATE_INVALID_UPDATE_STRUCT, // Struct in DS Update tree is of invalid - // type - DRAWSTATE_NUM_SAMPLES_MISMATCH, // Number of samples in bound PSO does not - // match number in FB of current RenderPass - DRAWSTATE_NO_END_COMMAND_BUFFER, // Must call vkEndCommandBuffer() before - // QueueSubmit on that commandBuffer - DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, // Binding cmds or calling End on CB that - // never had vkBeginCommandBuffer() - // called on it - DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, // Cmd Buffer created with - // VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT - // flag is submitted - // multiple times - DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, // vkCmdExecuteCommands() called - // with a primary commandBuffer - // in pCommandBuffers array - DRAWSTATE_VIEWPORT_NOT_BOUND, // Draw submitted with no viewport state bound - DRAWSTATE_SCISSOR_NOT_BOUND, // Draw submitted with no scissor state bound - DRAWSTATE_LINE_WIDTH_NOT_BOUND, // Draw submitted with no line width state - // bound - DRAWSTATE_DEPTH_BIAS_NOT_BOUND, // Draw submitted with no depth bias state - // bound - DRAWSTATE_BLEND_NOT_BOUND, // Draw submitted with no blend state bound when - // color write enabled - DRAWSTATE_DEPTH_BOUNDS_NOT_BOUND, // Draw submitted with no depth bounds - // state bound when depth enabled - DRAWSTATE_STENCIL_NOT_BOUND, // Draw submitted with no stencil state bound - // when stencil enabled - DRAWSTATE_INDEX_BUFFER_NOT_BOUND, // Draw submitted with no depth-stencil - // state bound when depth write enabled - DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, // Draw submitted PSO Pipeline - // layout that's not compatible - // with layout from - // BindDescriptorSets - DRAWSTATE_RENDERPASS_INCOMPATIBLE, // Incompatible renderpasses between - // secondary cmdBuffer and primary - // cmdBuffer or framebuffer - DRAWSTATE_FRAMEBUFFER_INCOMPATIBLE, // Incompatible framebuffer between - // secondary cmdBuffer and active - // renderPass - DRAWSTATE_INVALID_RENDERPASS, // Use of a NULL or otherwise invalid - // RenderPass object - DRAWSTATE_INVALID_RENDERPASS_CMD, // Invalid cmd submitted while a - // RenderPass is active - DRAWSTATE_NO_ACTIVE_RENDERPASS, // Rendering cmd submitted without an active - // RenderPass - DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, // DescriptorSet bound but it was - // never updated. This is a warning - // code. - DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, // DescriptorSet used by pipeline at - // draw time is not bound, or has been - // disturbed (which would have flagged - // previous warning) - DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, // DescriptorSets bound with - // different number of dynamic - // descriptors that were included in - // dynamicOffsetCount - DRAWSTATE_CLEAR_CMD_BEFORE_DRAW, // Clear cmd issued before any Draw in - // CommandBuffer, should use RenderPass Ops - // instead - DRAWSTATE_BEGIN_CB_INVALID_STATE, // CB state at Begin call is bad. Can be - // Primary/Secondary CB created with - // mismatched FB/RP information or CB in - // RECORDING state - DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, // CmdBuffer is being used in - // violation of - // VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT - // rules (i.e. simultaneous use w/o - // that bit set) - DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, // Attempting to call Reset (or - // Begin on recorded cmdBuffer) that - // was allocated from Pool w/o - // VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT - // bit set - DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, // Count for viewports and scissors - // mismatch and/or state doesn't match - // count - DRAWSTATE_INVALID_IMAGE_ASPECT, // Image aspect is invalid for the current - // operation - DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, // Attachment reference must be - // present in active subpass - DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, // A Descriptor of *_SAMPLER type is - // being updated with an invalid or bad - // Sampler - DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, // Descriptors of - // *COMBINED_IMAGE_SAMPLER - // type are being updated - // where some, but not all, - // of the updates use - // immutable samplers - DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, // A Descriptor of *_IMAGE or - // *_ATTACHMENT type is being updated - // with an invalid or bad ImageView - DRAWSTATE_BUFFERVIEW_DESCRIPTOR_ERROR, // A Descriptor of *_TEXEL_BUFFER - // type is being updated with an - // invalid or bad BufferView - DRAWSTATE_BUFFERINFO_DESCRIPTOR_ERROR, // A Descriptor of - // *_[UNIFORM|STORAGE]_BUFFER_[DYNAMIC] - // type is being updated with an - // invalid or bad BufferView - DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, // At draw time the dynamic offset - // combined with buffer offset and range - // oversteps size of buffer - DRAWSTATE_DOUBLE_DESTROY, // Destroying an object twice - DRAWSTATE_OBJECT_INUSE, // Destroying or modifying an object in use by a - // command buffer - DRAWSTATE_QUEUE_FORWARD_PROGRESS, // Queue cannot guarantee forward progress - DRAWSTATE_INVALID_UNIFORM_BUFFER_OFFSET, // Dynamic Uniform Buffer Offsets - // violate device limit - DRAWSTATE_INVALID_STORAGE_BUFFER_OFFSET, // Dynamic Storage Buffer Offsets - // violate device limit - DRAWSTATE_INDEPENDENT_BLEND, // If independent blending is not enabled, all - // elements of pAttachmentsMustBeIdentical - DRAWSTATE_DISABLED_LOGIC_OP, // If logic operations is not enabled, logicOpEnable - // must be VK_FALSE - DRAWSTATE_INVALID_LOGIC_OP, // If logicOpEnable is VK_TRUE, logicOp must - // must be a valid VkLogicOp value - DRAWSTATE_INVALID_QUEUE_INDEX, // Specified queue index exceeds number - // of queried queue families - DRAWSTATE_PUSH_CONSTANTS_ERROR, // Push constants exceed maxPushConstantSize -} DRAW_STATE_ERROR; - -typedef enum _SHADER_CHECKER_ERROR { - SHADER_CHECKER_NONE, - SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, // Type mismatch between shader stages or shader and pipeline - SHADER_CHECKER_OUTPUT_NOT_CONSUMED, // Entry appears in output interface, but missing in input - SHADER_CHECKER_INPUT_NOT_PRODUCED, // Entry appears in input interface, but missing in output - SHADER_CHECKER_NON_SPIRV_SHADER, // Shader image is not SPIR-V - SHADER_CHECKER_INCONSISTENT_SPIRV, // General inconsistency within a SPIR-V module - SHADER_CHECKER_UNKNOWN_STAGE, // Stage is not supported by analysis - SHADER_CHECKER_INCONSISTENT_VI, // VI state contains conflicting binding or attrib descriptions - SHADER_CHECKER_MISSING_DESCRIPTOR, // Shader attempts to use a descriptor binding not declared in the layout - SHADER_CHECKER_BAD_SPECIALIZATION, // Specialization map entry points outside specialization data block - SHADER_CHECKER_MISSING_ENTRYPOINT, // Shader module does not contain the requested entrypoint - SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, // Push constant variable is not in a push constant range - SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, // Push constant range exists, but not accessible from stage - SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, // Descriptor type does not match shader resource type - SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, // Descriptor used by shader, but not accessible from stage -} SHADER_CHECKER_ERROR; - -typedef enum _DRAW_TYPE { - DRAW = 0, - DRAW_INDEXED = 1, - DRAW_INDIRECT = 2, - DRAW_INDEXED_INDIRECT = 3, - DRAW_BEGIN_RANGE = DRAW, - DRAW_END_RANGE = DRAW_INDEXED_INDIRECT, - NUM_DRAW_TYPES = (DRAW_END_RANGE - DRAW_BEGIN_RANGE + 1), -} DRAW_TYPE; - -typedef struct _SHADER_DS_MAPPING { - uint32_t slotCount; - VkDescriptorSetLayoutCreateInfo *pShaderMappingSlot; -} SHADER_DS_MAPPING; - -typedef struct _GENERIC_HEADER { - VkStructureType sType; - const void *pNext; -} GENERIC_HEADER; - -typedef struct _PIPELINE_NODE { - VkPipeline pipeline; - VkGraphicsPipelineCreateInfo graphicsPipelineCI; - VkPipelineVertexInputStateCreateInfo vertexInputCI; - VkPipelineInputAssemblyStateCreateInfo iaStateCI; - VkPipelineTessellationStateCreateInfo tessStateCI; - VkPipelineViewportStateCreateInfo vpStateCI; - VkPipelineRasterizationStateCreateInfo rsStateCI; - VkPipelineMultisampleStateCreateInfo msStateCI; - VkPipelineColorBlendStateCreateInfo cbStateCI; - VkPipelineDepthStencilStateCreateInfo dsStateCI; - VkPipelineDynamicStateCreateInfo dynStateCI; - VkPipelineShaderStageCreateInfo vsCI; - VkPipelineShaderStageCreateInfo tcsCI; - VkPipelineShaderStageCreateInfo tesCI; - VkPipelineShaderStageCreateInfo gsCI; - VkPipelineShaderStageCreateInfo fsCI; - // Compute shader is include in VkComputePipelineCreateInfo - VkComputePipelineCreateInfo computePipelineCI; - // Flag of which shader stages are active for this pipeline - uint32_t active_shaders; - // Capture which sets are actually used by the shaders of this pipeline - std::set<unsigned> active_sets; - // Vtx input info (if any) - uint32_t vtxBindingCount; // number of bindings - VkVertexInputBindingDescription *pVertexBindingDescriptions; - uint32_t vtxAttributeCount; // number of attributes - VkVertexInputAttributeDescription *pVertexAttributeDescriptions; - uint32_t attachmentCount; // number of CB attachments - VkPipelineColorBlendAttachmentState *pAttachments; - // Default constructor - _PIPELINE_NODE() - : pipeline{}, graphicsPipelineCI{}, vertexInputCI{}, iaStateCI{}, tessStateCI{}, vpStateCI{}, rsStateCI{}, msStateCI{}, - cbStateCI{}, dsStateCI{}, dynStateCI{}, vsCI{}, tcsCI{}, tesCI{}, gsCI{}, fsCI{}, computePipelineCI{}, active_shaders(0), - vtxBindingCount(0), pVertexBindingDescriptions(0), vtxAttributeCount(0), pVertexAttributeDescriptions(0), - attachmentCount(0), pAttachments(0){}; -} PIPELINE_NODE; - -class BASE_NODE { - public: - std::atomic_int in_use; -}; - -typedef struct _SAMPLER_NODE { - VkSampler sampler; - VkSamplerCreateInfo createInfo; - - _SAMPLER_NODE(const VkSampler *ps, const VkSamplerCreateInfo *pci) : sampler(*ps), createInfo(*pci){}; -} SAMPLER_NODE; - -class IMAGE_NODE : public BASE_NODE { - public: - VkImageCreateInfo createInfo; - VkDeviceMemory mem; - VkDeviceSize memOffset; - VkDeviceSize memSize; -}; - -typedef struct _IMAGE_LAYOUT_NODE { - VkImageLayout layout; - VkFormat format; -} IMAGE_LAYOUT_NODE; - -typedef struct _IMAGE_CMD_BUF_LAYOUT_NODE { - VkImageLayout initialLayout; - VkImageLayout layout; -} IMAGE_CMD_BUF_LAYOUT_NODE; - -class BUFFER_NODE : public BASE_NODE { - public: - using BASE_NODE::in_use; - unique_ptr<VkBufferCreateInfo> create_info; -}; - -// Store the DAG. -struct DAGNode { - uint32_t pass; - std::vector<uint32_t> prev; - std::vector<uint32_t> next; -}; - -struct RENDER_PASS_NODE { - VkRenderPassCreateInfo const *pCreateInfo; - std::vector<bool> hasSelfDependency; - std::vector<DAGNode> subpassToNode; - vector<std::vector<VkFormat>> subpassColorFormats; - - RENDER_PASS_NODE(VkRenderPassCreateInfo const *pCreateInfo) : pCreateInfo(pCreateInfo) { - uint32_t i; - - subpassColorFormats.reserve(pCreateInfo->subpassCount); - for (i = 0; i < pCreateInfo->subpassCount; i++) { - const VkSubpassDescription *subpass = &pCreateInfo->pSubpasses[i]; - vector<VkFormat> color_formats; - uint32_t j; - - color_formats.reserve(subpass->colorAttachmentCount); - for (j = 0; j < subpass->colorAttachmentCount; j++) { - const uint32_t att = subpass->pColorAttachments[j].attachment; - const VkFormat format = pCreateInfo->pAttachments[att].format; - - color_formats.push_back(format); - } - - subpassColorFormats.push_back(color_formats); - } - } -}; - -class PHYS_DEV_PROPERTIES_NODE { - public: - VkPhysicalDeviceProperties properties; - VkPhysicalDeviceFeatures features; - vector<VkQueueFamilyProperties> queue_family_properties; -}; - -class FENCE_NODE : public BASE_NODE { - public: - using BASE_NODE::in_use; - VkQueue queue; - vector<VkCommandBuffer> cmdBuffers; - bool needsSignaled; - VkFence priorFence; - - // Default constructor - FENCE_NODE() : queue(NULL), needsSignaled(VK_FALSE), priorFence(static_cast<VkFence>(NULL)){}; -}; - -class SEMAPHORE_NODE : public BASE_NODE { - public: - using BASE_NODE::in_use; - uint32_t signaled; -}; - -class EVENT_NODE : public BASE_NODE { - public: - using BASE_NODE::in_use; - bool needsSignaled; - VkPipelineStageFlags stageMask; -}; - -class QUEUE_NODE { - public: - VkDevice device; - VkFence priorFence; - vector<VkCommandBuffer> untrackedCmdBuffers; - unordered_set<VkCommandBuffer> inFlightCmdBuffers; -}; - -class QUERY_POOL_NODE : public BASE_NODE { - public: - VkQueryPoolCreateInfo createInfo; -}; - -class FRAMEBUFFER_NODE { - public: - VkFramebufferCreateInfo createInfo; - unordered_set<VkCommandBuffer> referencingCmdBuffers; -}; - -// Descriptor Data structures -// Layout Node has the core layout data -typedef struct _LAYOUT_NODE { - VkDescriptorSetLayout layout; - VkDescriptorSetLayoutCreateInfo createInfo; - uint32_t startIndex; // 1st index of this layout - uint32_t endIndex; // last index of this layout - uint32_t dynamicDescriptorCount; // Total count of dynamic descriptors used - // by this layout - vector<VkDescriptorType> descriptorTypes; // Type per descriptor in this - // layout to verify correct - // updates - vector<VkShaderStageFlags> stageFlags; // stageFlags per descriptor in this - // layout to verify correct updates - unordered_map<uint32_t, uint32_t> bindingToIndexMap; // map set binding # to - // pBindings index - // Default constructor - _LAYOUT_NODE() : layout{}, createInfo{}, startIndex(0), endIndex(0), dynamicDescriptorCount(0){}; -} LAYOUT_NODE; - -// Store layouts and pushconstants for PipelineLayout -struct PIPELINE_LAYOUT_NODE { - vector<VkDescriptorSetLayout> descriptorSetLayouts; - vector<VkPushConstantRange> pushConstantRanges; -}; - -class SET_NODE : public BASE_NODE { - public: - using BASE_NODE::in_use; - VkDescriptorSet set; - VkDescriptorPool pool; - // Head of LL of all Update structs for this set - GENERIC_HEADER *pUpdateStructs; - // Total num of descriptors in this set (count of its layout plus all prior layouts) - uint32_t descriptorCount; - GENERIC_HEADER **ppDescriptors; // Array where each index points to update node for its slot - LAYOUT_NODE *pLayout; // Layout for this set - SET_NODE *pNext; - unordered_set<VkCommandBuffer> boundCmdBuffers; // Cmd buffers that this set has been bound to - SET_NODE() : pUpdateStructs(NULL), ppDescriptors(NULL), pLayout(NULL), pNext(NULL){}; -}; - -typedef struct _DESCRIPTOR_POOL_NODE { - VkDescriptorPool pool; - uint32_t maxSets; - VkDescriptorPoolCreateInfo createInfo; - SET_NODE *pSets; // Head of LL of sets for this Pool - vector<uint32_t> maxDescriptorTypeCount; // max # of descriptors of each type in this pool - vector<uint32_t> availableDescriptorTypeCount; // available # of descriptors of each type in this pool - - _DESCRIPTOR_POOL_NODE(const VkDescriptorPool pool, const VkDescriptorPoolCreateInfo *pCreateInfo) - : pool(pool), maxSets(pCreateInfo->maxSets), createInfo(*pCreateInfo), pSets(NULL), - maxDescriptorTypeCount(VK_DESCRIPTOR_TYPE_RANGE_SIZE), availableDescriptorTypeCount(VK_DESCRIPTOR_TYPE_RANGE_SIZE) { - if (createInfo.poolSizeCount) { // Shadow type struct from ptr into local struct - size_t poolSizeCountSize = createInfo.poolSizeCount * sizeof(VkDescriptorPoolSize); - createInfo.pPoolSizes = new VkDescriptorPoolSize[poolSizeCountSize]; - memcpy((void *)createInfo.pPoolSizes, pCreateInfo->pPoolSizes, poolSizeCountSize); - // Now set max counts for each descriptor type based on count of that type times maxSets - uint32_t i = 0; - for (i = 0; i < createInfo.poolSizeCount; ++i) { - uint32_t typeIndex = static_cast<uint32_t>(createInfo.pPoolSizes[i].type); - uint32_t poolSizeCount = createInfo.pPoolSizes[i].descriptorCount; - maxDescriptorTypeCount[typeIndex] += poolSizeCount; - } - for (i = 0; i < maxDescriptorTypeCount.size(); ++i) { - maxDescriptorTypeCount[i] *= createInfo.maxSets; - // Initially the available counts are equal to the max counts - availableDescriptorTypeCount[i] = maxDescriptorTypeCount[i]; - } - } else { - createInfo.pPoolSizes = NULL; // Make sure this is NULL so we don't try to clean it up - } - } - ~_DESCRIPTOR_POOL_NODE() { - delete[] createInfo.pPoolSizes; - // TODO : pSets are currently freed in deletePools function which uses freeShadowUpdateTree function - // need to migrate that struct to smart ptrs for auto-cleanup - } -} DESCRIPTOR_POOL_NODE; - -// Cmd Buffer Tracking -typedef enum _CMD_TYPE { - CMD_BINDPIPELINE, - CMD_BINDPIPELINEDELTA, - CMD_SETVIEWPORTSTATE, - CMD_SETSCISSORSTATE, - CMD_SETLINEWIDTHSTATE, - CMD_SETDEPTHBIASSTATE, - CMD_SETBLENDSTATE, - CMD_SETDEPTHBOUNDSSTATE, - CMD_SETSTENCILREADMASKSTATE, - CMD_SETSTENCILWRITEMASKSTATE, - CMD_SETSTENCILREFERENCESTATE, - CMD_BINDDESCRIPTORSETS, - CMD_BINDINDEXBUFFER, - CMD_BINDVERTEXBUFFER, - CMD_DRAW, - CMD_DRAWINDEXED, - CMD_DRAWINDIRECT, - CMD_DRAWINDEXEDINDIRECT, - CMD_DISPATCH, - CMD_DISPATCHINDIRECT, - CMD_COPYBUFFER, - CMD_COPYIMAGE, - CMD_BLITIMAGE, - CMD_COPYBUFFERTOIMAGE, - CMD_COPYIMAGETOBUFFER, - CMD_CLONEIMAGEDATA, - CMD_UPDATEBUFFER, - CMD_FILLBUFFER, - CMD_CLEARCOLORIMAGE, - CMD_CLEARATTACHMENTS, - CMD_CLEARDEPTHSTENCILIMAGE, - CMD_RESOLVEIMAGE, - CMD_SETEVENT, - CMD_RESETEVENT, - CMD_WAITEVENTS, - CMD_PIPELINEBARRIER, - CMD_BEGINQUERY, - CMD_ENDQUERY, - CMD_RESETQUERYPOOL, - CMD_COPYQUERYPOOLRESULTS, - CMD_WRITETIMESTAMP, - CMD_PUSHCONSTANTS, - CMD_INITATOMICCOUNTERS, - CMD_LOADATOMICCOUNTERS, - CMD_SAVEATOMICCOUNTERS, - CMD_BEGINRENDERPASS, - CMD_NEXTSUBPASS, - CMD_ENDRENDERPASS, - CMD_EXECUTECOMMANDS, -} CMD_TYPE; -// Data structure for holding sequence of cmds in cmd buffer -typedef struct _CMD_NODE { - CMD_TYPE type; - uint64_t cmdNumber; -} CMD_NODE; - -typedef enum _CB_STATE { - CB_NEW, // Newly created CB w/o any cmds - CB_RECORDING, // BeginCB has been called on this CB - CB_RECORDED, // EndCB has been called on this CB - CB_INVALID // CB had a bound descriptor set destroyed or updated -} CB_STATE; -// CB Status -- used to track status of various bindings on cmd buffer objects -typedef VkFlags CBStatusFlags; -typedef enum _CBStatusFlagBits { - CBSTATUS_NONE = 0x00000000, // No status is set - CBSTATUS_VIEWPORT_SET = 0x00000001, // Viewport has been set - CBSTATUS_LINE_WIDTH_SET = 0x00000002, // Line width has been set - CBSTATUS_DEPTH_BIAS_SET = 0x00000004, // Depth bias has been set - CBSTATUS_COLOR_BLEND_WRITE_ENABLE = 0x00000008, // PSO w/ CB Enable set has been set - CBSTATUS_BLEND_SET = 0x00000010, // Blend state object has been set - CBSTATUS_DEPTH_WRITE_ENABLE = 0x00000020, // PSO w/ Depth Enable set has been set - CBSTATUS_STENCIL_TEST_ENABLE = 0x00000040, // PSO w/ Stencil Enable set has been set - CBSTATUS_DEPTH_BOUNDS_SET = 0x00000080, // Depth bounds state object has been set - CBSTATUS_STENCIL_READ_MASK_SET = 0x00000100, // Stencil read mask has been set - CBSTATUS_STENCIL_WRITE_MASK_SET = 0x00000200, // Stencil write mask has been set - CBSTATUS_STENCIL_REFERENCE_SET = 0x00000400, // Stencil reference has been set - CBSTATUS_INDEX_BUFFER_BOUND = 0x00000800, // Index buffer has been set - CBSTATUS_SCISSOR_SET = 0x00001000, // Scissor has been set - CBSTATUS_ALL = 0x00001FFF, // All dynamic state set -} CBStatusFlagBits; - -typedef struct stencil_data { - uint32_t compareMask; - uint32_t writeMask; - uint32_t reference; -} CBStencilData; - -typedef struct _DRAW_DATA { vector<VkBuffer> buffers; } DRAW_DATA; - -struct ImageSubresourcePair { - VkImage image; - bool hasSubresource; - VkImageSubresource subresource; -}; - -bool operator==(const ImageSubresourcePair &img1, const ImageSubresourcePair &img2) { - if (img1.image != img2.image || img1.hasSubresource != img2.hasSubresource) - return false; - return !img1.hasSubresource || - (img1.subresource.aspectMask == img2.subresource.aspectMask && img1.subresource.mipLevel == img2.subresource.mipLevel && - img1.subresource.arrayLayer == img2.subresource.arrayLayer); -} - -namespace std { -template <> struct hash<ImageSubresourcePair> { - size_t operator()(ImageSubresourcePair img) const throw() { - size_t hashVal = hash<uint64_t>()(reinterpret_cast<uint64_t &>(img.image)); - hashVal ^= hash<bool>()(img.hasSubresource); - if (img.hasSubresource) { - hashVal ^= hash<uint32_t>()(reinterpret_cast<uint32_t &>(img.subresource.aspectMask)); - hashVal ^= hash<uint32_t>()(img.subresource.mipLevel); - hashVal ^= hash<uint32_t>()(img.subresource.arrayLayer); - } - return hashVal; - } -}; -} - -struct QueryObject { - VkQueryPool pool; - uint32_t index; -}; - -bool operator==(const QueryObject &query1, const QueryObject &query2) { - return (query1.pool == query2.pool && query1.index == query2.index); -} - -namespace std { -template <> struct hash<QueryObject> { - size_t operator()(QueryObject query) const throw() { - return hash<uint64_t>()((uint64_t)(query.pool)) ^ hash<uint32_t>()(query.index); - } -}; -} - -// Cmd Buffer Wrapper Struct -typedef struct _GLOBAL_CB_NODE { - VkCommandBuffer commandBuffer; - VkCommandBufferAllocateInfo createInfo; - VkCommandBufferBeginInfo beginInfo; - VkCommandBufferInheritanceInfo inheritanceInfo; - VkFence fence; // fence tracking this cmd buffer - VkDevice device; // device this DB belongs to - uint64_t numCmds; // number of cmds in this CB - uint64_t drawCount[NUM_DRAW_TYPES]; // Count of each type of draw in this CB - CB_STATE state; // Track cmd buffer update state - uint64_t submitCount; // Number of times CB has been submitted - CBStatusFlags status; // Track status of various bindings on cmd buffer - vector<CMD_NODE> cmds; // vector of commands bound to this command buffer - // Currently storing "lastBound" objects on per-CB basis - // long-term may want to create caches of "lastBound" states and could have - // each individual CMD_NODE referencing its own "lastBound" state - VkPipeline lastBoundPipeline; - uint32_t lastVtxBinding; - vector<VkBuffer> boundVtxBuffers; - vector<VkViewport> viewports; - vector<VkRect2D> scissors; - float lineWidth; - float depthBiasConstantFactor; - float depthBiasClamp; - float depthBiasSlopeFactor; - float blendConstants[4]; - float minDepthBounds; - float maxDepthBounds; - CBStencilData front; - CBStencilData back; - VkDescriptorSet lastBoundDescriptorSet; - VkPipelineLayout lastBoundPipelineLayout; - VkRenderPassBeginInfo activeRenderPassBeginInfo; - VkRenderPass activeRenderPass; - VkSubpassContents activeSubpassContents; - uint32_t activeSubpass; - VkFramebuffer framebuffer; - // Capture unique std::set of descriptorSets that are bound to this CB. - std::set<VkDescriptorSet> uniqueBoundSets; - // Track descriptor sets that are destroyed or updated while bound to CB - // TODO : These data structures relate to tracking resources that invalidate - // a cmd buffer that references them. Need to unify how we handle these - // cases so we don't have different tracking data for each type. - std::set<VkDescriptorSet> destroyedSets; - std::set<VkDescriptorSet> updatedSets; - unordered_set<VkFramebuffer> destroyedFramebuffers; - // Keep running track of which sets are bound to which set# at any given - // time - vector<VkDescriptorSet> boundDescriptorSets; // Index is set# that given set is bound to - vector<VkEvent> waitedEvents; - vector<VkSemaphore> semaphores; - vector<VkEvent> events; - unordered_map<QueryObject, vector<VkEvent>> waitedEventsBeforeQueryReset; - unordered_map<QueryObject, bool> queryToStateMap; // 0 is unavailable, 1 is available - unordered_set<QueryObject> activeQueries; - unordered_set<QueryObject> startedQueries; - unordered_map<ImageSubresourcePair, IMAGE_CMD_BUF_LAYOUT_NODE> imageLayoutMap; - unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap; - unordered_map<VkEvent, VkPipelineStageFlags> eventToStageMap; - vector<DRAW_DATA> drawData; - DRAW_DATA currentDrawData; - VkCommandBuffer primaryCommandBuffer; - // If cmd buffer is primary, track secondary command buffers pending - // execution - std::unordered_set<VkCommandBuffer> secondaryCommandBuffers; - vector<uint32_t> dynamicOffsets; // one dynamic offset per dynamic descriptor bound to this CB -} GLOBAL_CB_NODE; - -typedef struct _SWAPCHAIN_NODE { - VkSwapchainCreateInfoKHR createInfo; - uint32_t *pQueueFamilyIndices; - std::vector<VkImage> images; - _SWAPCHAIN_NODE(const VkSwapchainCreateInfoKHR *pCreateInfo) : createInfo(*pCreateInfo), pQueueFamilyIndices(NULL) { - if (pCreateInfo->queueFamilyIndexCount && pCreateInfo->imageSharingMode == VK_SHARING_MODE_CONCURRENT) { - pQueueFamilyIndices = new uint32_t[pCreateInfo->queueFamilyIndexCount]; - memcpy(pQueueFamilyIndices, pCreateInfo->pQueueFamilyIndices, pCreateInfo->queueFamilyIndexCount * sizeof(uint32_t)); - createInfo.pQueueFamilyIndices = pQueueFamilyIndices; - } - } - ~_SWAPCHAIN_NODE() { delete pQueueFamilyIndices; } -} SWAPCHAIN_NODE; diff --git a/layers/linux/VkLayer_draw_state.json b/layers/linux/VkLayer_draw_state.json deleted file mode 100644 index c778a56f..00000000 --- a/layers/linux/VkLayer_draw_state.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "file_format_version" : "1.0.0", - "layer" : { - "name": "VK_LAYER_LUNARG_draw_state", - "type": "GLOBAL", - "library_path": "./libVkLayer_draw_state.so", - "api_version": "1.0.5", - "implementation_version": "1", - "description": "LunarG Validation Layer", - "instance_extensions": [ - { - "name": "VK_EXT_debug_report", - "spec_version": "2" - } - ] - } -} diff --git a/layers/linux/VkLayer_mem_tracker.json b/layers/linux/VkLayer_mem_tracker.json deleted file mode 100644 index b2062e16..00000000 --- a/layers/linux/VkLayer_mem_tracker.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "file_format_version" : "1.0.0", - "layer" : { - "name": "VK_LAYER_LUNARG_mem_tracker", - "type": "GLOBAL", - "library_path": "./libVkLayer_mem_tracker.so", - "api_version": "1.0.5", - "implementation_version": "1", - "description": "LunarG Validation Layer", - "instance_extensions": [ - { - "name": "VK_EXT_debug_report", - "spec_version": "2" - } - ] - } -} diff --git a/layers/mem_tracker.cpp b/layers/mem_tracker.cpp deleted file mode 100644 index 6af41738..00000000 --- a/layers/mem_tracker.cpp +++ /dev/null @@ -1,3257 +0,0 @@ -/* Copyright (c) 2015-2016 The Khronos Group Inc. - * Copyright (c) 2015-2016 Valve Corporation - * Copyright (c) 2015-2016 LunarG, Inc. - * Copyright (C) 2015-2016 Google Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and/or associated documentation files (the "Materials"), to - * deal in the Materials without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Materials, and to permit persons to whom the Materials - * are furnished to do so, subject to the following conditions: - * - * The above copyright notice(s) and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE - * USE OR OTHER DEALINGS IN THE MATERIALS - * - * Author: Cody Northrop <cody@lunarg.com> - * Author: Jon Ashburn <jon@lunarg.com> - * Author: Mark Lobodzinski <mark@lunarg.com> - * Author: Tobin Ehlis <tobin@lunarg.com> - */ - -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <functional> -#include <list> -#include <map> -#include <vector> -using namespace std; - -#include "vk_loader_platform.h" -#include "vk_dispatch_table_helper.h" -#include "vk_struct_string_helper_cpp.h" -#include "mem_tracker.h" -#include "vk_layer_config.h" -#include "vk_layer_extension_utils.h" -#include "vk_layer_table.h" -#include "vk_layer_data.h" -#include "vk_layer_logging.h" - -// WSI Image Objects bypass usual Image Object creation methods. A special Memory -// Object value will be used to identify them internally. -static const VkDeviceMemory MEMTRACKER_SWAP_CHAIN_IMAGE_KEY = (VkDeviceMemory)(-1); - -struct layer_data { - debug_report_data *report_data; - std::vector<VkDebugReportCallbackEXT> logging_callback; - VkLayerDispatchTable *device_dispatch_table; - VkLayerInstanceDispatchTable *instance_dispatch_table; - VkBool32 wsi_enabled; - uint64_t currentFenceId; - VkPhysicalDeviceProperties properties; - unordered_map<VkDeviceMemory, vector<MEMORY_RANGE>> bufferRanges, imageRanges; - // Maps for tracking key structs related to mem_tracker state - unordered_map<VkCommandBuffer, MT_CB_INFO> cbMap; - unordered_map<VkCommandPool, MT_CMD_POOL_INFO> commandPoolMap; - unordered_map<VkDeviceMemory, MT_MEM_OBJ_INFO> memObjMap; - unordered_map<VkFence, MT_FENCE_INFO> fenceMap; - unordered_map<VkQueue, MT_QUEUE_INFO> queueMap; - unordered_map<VkSwapchainKHR, MT_SWAP_CHAIN_INFO *> swapchainMap; - unordered_map<VkSemaphore, MtSemaphoreState> semaphoreMap; - unordered_map<VkFramebuffer, MT_FB_INFO> fbMap; - unordered_map<VkRenderPass, MT_PASS_INFO> passMap; - unordered_map<VkImageView, MT_IMAGE_VIEW_INFO> imageViewMap; - unordered_map<VkDescriptorSet, MT_DESCRIPTOR_SET_INFO> descriptorSetMap; - // Images and Buffers are 2 objects that can have memory bound to them so they get special treatment - unordered_map<uint64_t, MT_OBJ_BINDING_INFO> imageMap; - unordered_map<uint64_t, MT_OBJ_BINDING_INFO> bufferMap; - unordered_map<VkBufferView, VkBufferViewCreateInfo> bufferViewMap; - - layer_data() - : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), wsi_enabled(VK_FALSE), - currentFenceId(1){}; -}; - -static unordered_map<void *, layer_data *> layer_data_map; - -static VkPhysicalDeviceMemoryProperties memProps; - -static VkBool32 clear_cmd_buf_and_mem_references(layer_data *my_data, const VkCommandBuffer cb); - -// TODO : This can be much smarter, using separate locks for separate global data -static int globalLockInitialized = 0; -static loader_platform_thread_mutex globalLock; - -#define MAX_BINDING 0xFFFFFFFF - -static MT_OBJ_BINDING_INFO *get_object_binding_info(layer_data *my_data, uint64_t handle, VkDebugReportObjectTypeEXT type) { - MT_OBJ_BINDING_INFO *retValue = NULL; - switch (type) { - case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: { - auto it = my_data->imageMap.find(handle); - if (it != my_data->imageMap.end()) - return &(*it).second; - break; - } - case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: { - auto it = my_data->bufferMap.find(handle); - if (it != my_data->bufferMap.end()) - return &(*it).second; - break; - } - default: - break; - } - return retValue; -} - -template layer_data *get_my_data_ptr<layer_data>(void *data_key, std::unordered_map<void *, layer_data *> &data_map); - -// Add new queue for this device to map container -static void add_queue_info(layer_data *my_data, const VkQueue queue) { - MT_QUEUE_INFO *pInfo = &my_data->queueMap[queue]; - pInfo->lastRetiredId = 0; - pInfo->lastSubmittedId = 0; -} - -static void delete_queue_info_list(layer_data *my_data) { - // Process queue list, cleaning up each entry before deleting - my_data->queueMap.clear(); -} - -static void add_swap_chain_info(layer_data *my_data, const VkSwapchainKHR swapchain, const VkSwapchainCreateInfoKHR *pCI) { - MT_SWAP_CHAIN_INFO *pInfo = new MT_SWAP_CHAIN_INFO; - memcpy(&pInfo->createInfo, pCI, sizeof(VkSwapchainCreateInfoKHR)); - my_data->swapchainMap[swapchain] = pInfo; -} - -// Add new CBInfo for this cb to map container -static void add_cmd_buf_info(layer_data *my_data, VkCommandPool commandPool, const VkCommandBuffer cb) { - my_data->cbMap[cb].commandBuffer = cb; - my_data->commandPoolMap[commandPool].pCommandBuffers.push_front(cb); -} - -// Delete CBInfo from container and clear mem references to CB -static VkBool32 delete_cmd_buf_info(layer_data *my_data, VkCommandPool commandPool, const VkCommandBuffer cb) { - VkBool32 result = VK_TRUE; - result = clear_cmd_buf_and_mem_references(my_data, cb); - // Delete the CBInfo info - if (result != VK_TRUE) { - my_data->commandPoolMap[commandPool].pCommandBuffers.remove(cb); - my_data->cbMap.erase(cb); - } - return result; -} - -// Return ptr to Info in CB map, or NULL if not found -static MT_CB_INFO *get_cmd_buf_info(layer_data *my_data, const VkCommandBuffer cb) { - auto item = my_data->cbMap.find(cb); - if (item != my_data->cbMap.end()) { - return &(*item).second; - } else { - return NULL; - } -} - -static void add_object_binding_info(layer_data *my_data, const uint64_t handle, const VkDebugReportObjectTypeEXT type, - const VkDeviceMemory mem) { - switch (type) { - // Buffers and images are unique as their CreateInfo is in container struct - case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: { - auto pCI = &my_data->bufferMap[handle]; - pCI->mem = mem; - break; - } - case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: { - auto pCI = &my_data->imageMap[handle]; - pCI->mem = mem; - break; - } - default: - break; - } -} - -static void add_object_create_info(layer_data *my_data, const uint64_t handle, const VkDebugReportObjectTypeEXT type, - const void *pCreateInfo) { - // TODO : For any CreateInfo struct that has ptrs, need to deep copy them and appropriately clean up on Destroy - switch (type) { - // Buffers and images are unique as their CreateInfo is in container struct - case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: { - auto pCI = &my_data->bufferMap[handle]; - memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO)); - memcpy(&pCI->create_info.buffer, pCreateInfo, sizeof(VkBufferCreateInfo)); - break; - } - case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: { - auto pCI = &my_data->imageMap[handle]; - memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO)); - memcpy(&pCI->create_info.image, pCreateInfo, sizeof(VkImageCreateInfo)); - break; - } - // Swap Chain is very unique, use my_data->imageMap, but copy in - // SwapChainCreatInfo's usage flags and set the mem value to a unique key. These is used by - // vkCreateImageView and internal mem_tracker routines to distinguish swap chain images - case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: { - auto pCI = &my_data->imageMap[handle]; - memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO)); - pCI->mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY; - pCI->valid = false; - pCI->create_info.image.usage = - const_cast<VkSwapchainCreateInfoKHR *>(static_cast<const VkSwapchainCreateInfoKHR *>(pCreateInfo))->imageUsage; - break; - } - default: - break; - } -} - -// Add a fence, creating one if necessary to our list of fences/fenceIds -static VkBool32 add_fence_info(layer_data *my_data, VkFence fence, VkQueue queue, uint64_t *fenceId) { - VkBool32 skipCall = VK_FALSE; - *fenceId = my_data->currentFenceId++; - - // If no fence, create an internal fence to track the submissions - if (fence != VK_NULL_HANDLE) { - my_data->fenceMap[fence].fenceId = *fenceId; - my_data->fenceMap[fence].queue = queue; - // Validate that fence is in UNSIGNALED state - VkFenceCreateInfo *pFenceCI = &(my_data->fenceMap[fence].createInfo); - if (pFenceCI->flags & VK_FENCE_CREATE_SIGNALED_BIT) { - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, - (uint64_t)fence, __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", - "Fence %#" PRIxLEAST64 " submitted in SIGNALED state. Fences must be reset before being submitted", - (uint64_t)fence); - } - } else { - // TODO : Do we need to create an internal fence here for tracking purposes? - } - // Update most recently submitted fence and fenceId for Queue - my_data->queueMap[queue].lastSubmittedId = *fenceId; - return skipCall; -} - -// Remove a fenceInfo from our list of fences/fenceIds -static void delete_fence_info(layer_data *my_data, VkFence fence) { my_data->fenceMap.erase(fence); } - -// Record information when a fence is known to be signalled -static void update_fence_tracking(layer_data *my_data, VkFence fence) { - auto fence_item = my_data->fenceMap.find(fence); - if (fence_item != my_data->fenceMap.end()) { - MT_FENCE_INFO *pCurFenceInfo = &(*fence_item).second; - VkQueue queue = pCurFenceInfo->queue; - auto queue_item = my_data->queueMap.find(queue); - if (queue_item != my_data->queueMap.end()) { - MT_QUEUE_INFO *pQueueInfo = &(*queue_item).second; - if (pQueueInfo->lastRetiredId < pCurFenceInfo->fenceId) { - pQueueInfo->lastRetiredId = pCurFenceInfo->fenceId; - } - } - } - - // Update fence state in fenceCreateInfo structure - auto pFCI = &(my_data->fenceMap[fence].createInfo); - pFCI->flags = static_cast<VkFenceCreateFlags>(pFCI->flags | VK_FENCE_CREATE_SIGNALED_BIT); -} - -// Helper routine that updates the fence list for a specific queue to all-retired -static void retire_queue_fences(layer_data *my_data, VkQueue queue) { - MT_QUEUE_INFO *pQueueInfo = &my_data->queueMap[queue]; - // Set queue's lastRetired to lastSubmitted indicating all fences completed - pQueueInfo->lastRetiredId = pQueueInfo->lastSubmittedId; -} - -// Helper routine that updates all queues to all-retired -static void retire_device_fences(layer_data *my_data, VkDevice device) { - // Process each queue for device - // TODO: Add multiple device support - for (auto ii = my_data->queueMap.begin(); ii != my_data->queueMap.end(); ++ii) { - // Set queue's lastRetired to lastSubmitted indicating all fences completed - MT_QUEUE_INFO *pQueueInfo = &(*ii).second; - pQueueInfo->lastRetiredId = pQueueInfo->lastSubmittedId; - } -} - -// Helper function to validate correct usage bits set for buffers or images -// Verify that (actual & desired) flags != 0 or, -// if strict is true, verify that (actual & desired) flags == desired -// In case of error, report it via dbg callbacks -static VkBool32 validate_usage_flags(layer_data *my_data, void *disp_obj, VkFlags actual, VkFlags desired, VkBool32 strict, - uint64_t obj_handle, VkDebugReportObjectTypeEXT obj_type, char const *ty_str, - char const *func_name, char const *usage_str) { - VkBool32 correct_usage = VK_FALSE; - VkBool32 skipCall = VK_FALSE; - if (strict) - correct_usage = ((actual & desired) == desired); - else - correct_usage = ((actual & desired) != 0); - if (!correct_usage) { - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_type, obj_handle, __LINE__, - MEMTRACK_INVALID_USAGE_FLAG, "MEM", "Invalid usage flag for %s %#" PRIxLEAST64 - " used by %s. In this case, %s should have %s set during creation.", - ty_str, obj_handle, func_name, ty_str, usage_str); - } - return skipCall; -} - -// Helper function to validate usage flags for images -// Pulls image info and then sends actual vs. desired usage off to helper above where -// an error will be flagged if usage is not correct -static VkBool32 validate_image_usage_flags(layer_data *my_data, void *disp_obj, VkImage image, VkFlags desired, VkBool32 strict, - char const *func_name, char const *usage_string) { - VkBool32 skipCall = VK_FALSE; - MT_OBJ_BINDING_INFO *pBindInfo = get_object_binding_info(my_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); - if (pBindInfo) { - skipCall = validate_usage_flags(my_data, disp_obj, pBindInfo->create_info.image.usage, desired, strict, (uint64_t)image, - VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "image", func_name, usage_string); - } - return skipCall; -} - -// Helper function to validate usage flags for buffers -// Pulls buffer info and then sends actual vs. desired usage off to helper above where -// an error will be flagged if usage is not correct -static VkBool32 validate_buffer_usage_flags(layer_data *my_data, void *disp_obj, VkBuffer buffer, VkFlags desired, VkBool32 strict, - char const *func_name, char const *usage_string) { - VkBool32 skipCall = VK_FALSE; - MT_OBJ_BINDING_INFO *pBindInfo = get_object_binding_info(my_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT); - if (pBindInfo) { - skipCall = validate_usage_flags(my_data, disp_obj, pBindInfo->create_info.buffer.usage, desired, strict, (uint64_t)buffer, - VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "buffer", func_name, usage_string); - } - return skipCall; -} - -// Return ptr to info in map container containing mem, or NULL if not found -// Calls to this function should be wrapped in mutex -static MT_MEM_OBJ_INFO *get_mem_obj_info(layer_data *my_data, const VkDeviceMemory mem) { - auto item = my_data->memObjMap.find(mem); - if (item != my_data->memObjMap.end()) { - return &(*item).second; - } else { - return NULL; - } -} - -static void add_mem_obj_info(layer_data *my_data, void *object, const VkDeviceMemory mem, - const VkMemoryAllocateInfo *pAllocateInfo) { - assert(object != NULL); - - memcpy(&my_data->memObjMap[mem].allocInfo, pAllocateInfo, sizeof(VkMemoryAllocateInfo)); - // TODO: Update for real hardware, actually process allocation info structures - my_data->memObjMap[mem].allocInfo.pNext = NULL; - my_data->memObjMap[mem].object = object; - my_data->memObjMap[mem].refCount = 0; - my_data->memObjMap[mem].mem = mem; - my_data->memObjMap[mem].memRange.offset = 0; - my_data->memObjMap[mem].memRange.size = 0; - my_data->memObjMap[mem].pData = 0; - my_data->memObjMap[mem].pDriverData = 0; - my_data->memObjMap[mem].valid = false; -} - -static VkBool32 validate_memory_is_valid(layer_data *my_data, VkDeviceMemory mem, const char *functionName, - VkImage image = VK_NULL_HANDLE) { - if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) { - MT_OBJ_BINDING_INFO *pBindInfo = get_object_binding_info(my_data, (uint64_t)(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); - if (pBindInfo && !pBindInfo->valid) { - return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, - (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM", - "%s: Cannot read invalid swapchain image %" PRIx64 ", please fill the memory before using.", - functionName, (uint64_t)(image)); - } - } else { - MT_MEM_OBJ_INFO *pMemObj = get_mem_obj_info(my_data, mem); - if (pMemObj && !pMemObj->valid) { - return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, - (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM", - "%s: Cannot read invalid memory %" PRIx64 ", please fill the memory before using.", functionName, - (uint64_t)(mem)); - } - } - return false; -} - -static void set_memory_valid(layer_data *my_data, VkDeviceMemory mem, bool valid, VkImage image = VK_NULL_HANDLE) { - if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) { - MT_OBJ_BINDING_INFO *pBindInfo = get_object_binding_info(my_data, (uint64_t)(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); - if (pBindInfo) { - pBindInfo->valid = valid; - } - } else { - MT_MEM_OBJ_INFO *pMemObj = get_mem_obj_info(my_data, mem); - if (pMemObj) { - pMemObj->valid = valid; - } - } -} - -// Find CB Info and add mem reference to list container -// Find Mem Obj Info and add CB reference to list container -static VkBool32 update_cmd_buf_and_mem_references(layer_data *my_data, const VkCommandBuffer cb, const VkDeviceMemory mem, - const char *apiName) { - VkBool32 skipCall = VK_FALSE; - - // Skip validation if this image was created through WSI - if (mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) { - - // First update CB binding in MemObj mini CB list - MT_MEM_OBJ_INFO *pMemInfo = get_mem_obj_info(my_data, mem); - if (pMemInfo) { - // Search for cmd buffer object in memory object's binding list - VkBool32 found = VK_FALSE; - if (pMemInfo->pCommandBufferBindings.size() > 0) { - for (list<VkCommandBuffer>::iterator it = pMemInfo->pCommandBufferBindings.begin(); - it != pMemInfo->pCommandBufferBindings.end(); ++it) { - if ((*it) == cb) { - found = VK_TRUE; - break; - } - } - } - // If not present, add to list - if (found == VK_FALSE) { - pMemInfo->pCommandBufferBindings.push_front(cb); - pMemInfo->refCount++; - } - // Now update CBInfo's Mem reference list - MT_CB_INFO *pCBInfo = get_cmd_buf_info(my_data, cb); - // TODO: keep track of all destroyed CBs so we know if this is a stale or simply invalid object - if (pCBInfo) { - // Search for memory object in cmd buffer's reference list - VkBool32 found = VK_FALSE; - if (pCBInfo->pMemObjList.size() > 0) { - for (auto it = pCBInfo->pMemObjList.begin(); it != pCBInfo->pMemObjList.end(); ++it) { - if ((*it) == mem) { - found = VK_TRUE; - break; - } - } - } - // If not present, add to list - if (found == VK_FALSE) { - pCBInfo->pMemObjList.push_front(mem); - } - } - } - } - return skipCall; -} - -// Free bindings related to CB -static VkBool32 clear_cmd_buf_and_mem_references(layer_data *my_data, const VkCommandBuffer cb) { - VkBool32 skipCall = VK_FALSE; - MT_CB_INFO *pCBInfo = get_cmd_buf_info(my_data, cb); - - if (pCBInfo) { - if (pCBInfo->pMemObjList.size() > 0) { - list<VkDeviceMemory> mem_obj_list = pCBInfo->pMemObjList; - for (list<VkDeviceMemory>::iterator it = mem_obj_list.begin(); it != mem_obj_list.end(); ++it) { - MT_MEM_OBJ_INFO *pInfo = get_mem_obj_info(my_data, *it); - if (pInfo) { - pInfo->pCommandBufferBindings.remove(cb); - pInfo->refCount--; - } - } - pCBInfo->pMemObjList.clear(); - } - pCBInfo->activeDescriptorSets.clear(); - pCBInfo->validate_functions.clear(); - } - return skipCall; -} - -// Delete the entire CB list -static VkBool32 delete_cmd_buf_info_list(layer_data *my_data) { - VkBool32 skipCall = VK_FALSE; - for (unordered_map<VkCommandBuffer, MT_CB_INFO>::iterator ii = my_data->cbMap.begin(); ii != my_data->cbMap.end(); ++ii) { - skipCall |= clear_cmd_buf_and_mem_references(my_data, (*ii).first); - } - my_data->cbMap.clear(); - return skipCall; -} - -// For given MemObjInfo, report Obj & CB bindings -static VkBool32 reportMemReferencesAndCleanUp(layer_data *my_data, MT_MEM_OBJ_INFO *pMemObjInfo) { - VkBool32 skipCall = VK_FALSE; - size_t cmdBufRefCount = pMemObjInfo->pCommandBufferBindings.size(); - size_t objRefCount = pMemObjInfo->pObjBindings.size(); - - if ((pMemObjInfo->pCommandBufferBindings.size()) != 0) { - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, - (uint64_t)pMemObjInfo->mem, __LINE__, MEMTRACK_FREED_MEM_REF, "MEM", - "Attempting to free memory object %#" PRIxLEAST64 " which still contains " PRINTF_SIZE_T_SPECIFIER - " references", - (uint64_t)pMemObjInfo->mem, (cmdBufRefCount + objRefCount)); - } - - if (cmdBufRefCount > 0 && pMemObjInfo->pCommandBufferBindings.size() > 0) { - for (list<VkCommandBuffer>::const_iterator it = pMemObjInfo->pCommandBufferBindings.begin(); - it != pMemObjInfo->pCommandBufferBindings.end(); ++it) { - // TODO : CommandBuffer should be source Obj here - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)(*it), __LINE__, MEMTRACK_FREED_MEM_REF, "MEM", - "Command Buffer %p still has a reference to mem obj %#" PRIxLEAST64, (*it), (uint64_t)pMemObjInfo->mem); - } - // Clear the list of hanging references - pMemObjInfo->pCommandBufferBindings.clear(); - } - - if (objRefCount > 0 && pMemObjInfo->pObjBindings.size() > 0) { - for (auto it = pMemObjInfo->pObjBindings.begin(); it != pMemObjInfo->pObjBindings.end(); ++it) { - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, it->type, it->handle, __LINE__, - MEMTRACK_FREED_MEM_REF, "MEM", "VK Object %#" PRIxLEAST64 " still has a reference to mem obj %#" PRIxLEAST64, - it->handle, (uint64_t)pMemObjInfo->mem); - } - // Clear the list of hanging references - pMemObjInfo->pObjBindings.clear(); - } - return skipCall; -} - -static VkBool32 deleteMemObjInfo(layer_data *my_data, void *object, VkDeviceMemory mem) { - VkBool32 skipCall = VK_FALSE; - auto item = my_data->memObjMap.find(mem); - if (item != my_data->memObjMap.end()) { - my_data->memObjMap.erase(item); - } else { - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, - (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM", - "Request to delete memory object %#" PRIxLEAST64 " not present in memory Object Map", (uint64_t)mem); - } - return skipCall; -} - -// Check if fence for given CB is completed -static VkBool32 checkCBCompleted(layer_data *my_data, const VkCommandBuffer cb, VkBool32 *complete) { - MT_CB_INFO *pCBInfo = get_cmd_buf_info(my_data, cb); - VkBool32 skipCall = VK_FALSE; - *complete = VK_TRUE; - - if (pCBInfo) { - if (pCBInfo->lastSubmittedQueue != NULL) { - VkQueue queue = pCBInfo->lastSubmittedQueue; - MT_QUEUE_INFO *pQueueInfo = &my_data->queueMap[queue]; - if (pCBInfo->fenceId > pQueueInfo->lastRetiredId) { - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)cb, __LINE__, MEMTRACK_NONE, "MEM", - "fence %#" PRIxLEAST64 " for CB %p has not been checked for completion", - (uint64_t)pCBInfo->lastSubmittedFence, cb); - *complete = VK_FALSE; - } - } - } - return skipCall; -} - -static VkBool32 freeMemObjInfo(layer_data *my_data, void *object, VkDeviceMemory mem, VkBool32 internal) { - VkBool32 skipCall = VK_FALSE; - // Parse global list to find info w/ mem - MT_MEM_OBJ_INFO *pInfo = get_mem_obj_info(my_data, mem); - if (pInfo) { - if (pInfo->allocInfo.allocationSize == 0 && !internal) { - // TODO: Verify against Valid Use section - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, - (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM", - "Attempting to free memory associated with a Persistent Image, %#" PRIxLEAST64 ", " - "this should not be explicitly freed\n", - (uint64_t)mem); - } else { - // Clear any CB bindings for completed CBs - // TODO : Is there a better place to do this? - - VkBool32 commandBufferComplete = VK_FALSE; - assert(pInfo->object != VK_NULL_HANDLE); - list<VkCommandBuffer>::iterator it = pInfo->pCommandBufferBindings.begin(); - list<VkCommandBuffer>::iterator temp; - while (pInfo->pCommandBufferBindings.size() > 0 && it != pInfo->pCommandBufferBindings.end()) { - skipCall |= checkCBCompleted(my_data, *it, &commandBufferComplete); - if (VK_TRUE == commandBufferComplete) { - temp = it; - ++temp; - skipCall |= clear_cmd_buf_and_mem_references(my_data, *it); - it = temp; - } else { - ++it; - } - } - - // Now verify that no references to this mem obj remain and remove bindings - if (0 != pInfo->refCount) { - skipCall |= reportMemReferencesAndCleanUp(my_data, pInfo); - } - // Delete mem obj info - skipCall |= deleteMemObjInfo(my_data, object, mem); - } - } - return skipCall; -} - -static const char *object_type_to_string(VkDebugReportObjectTypeEXT type) { - switch (type) { - case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: - return "image"; - break; - case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: - return "buffer"; - break; - case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: - return "swapchain"; - break; - default: - return "unknown"; - } -} - -// Remove object binding performs 3 tasks: -// 1. Remove ObjectInfo from MemObjInfo list container of obj bindings & free it -// 2. Decrement refCount for MemObjInfo -// 3. Clear mem binding for image/buffer by setting its handle to 0 -// TODO : This only applied to Buffer, Image, and Swapchain objects now, how should it be updated/customized? -static VkBool32 clear_object_binding(layer_data *my_data, void *dispObj, uint64_t handle, VkDebugReportObjectTypeEXT type) { - // TODO : Need to customize images/buffers/swapchains to track mem binding and clear it here appropriately - VkBool32 skipCall = VK_FALSE; - MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(my_data, handle, type); - if (pObjBindInfo) { - MT_MEM_OBJ_INFO *pMemObjInfo = get_mem_obj_info(my_data, pObjBindInfo->mem); - // TODO : Make sure this is a reasonable way to reset mem binding - pObjBindInfo->mem = VK_NULL_HANDLE; - if (pMemObjInfo) { - // This obj is bound to a memory object. Remove the reference to this object in that memory object's list, decrement the - // memObj's refcount - // and set the objects memory binding pointer to NULL. - VkBool32 clearSucceeded = VK_FALSE; - for (auto it = pMemObjInfo->pObjBindings.begin(); it != pMemObjInfo->pObjBindings.end(); ++it) { - if ((it->handle == handle) && (it->type == type)) { - pMemObjInfo->refCount--; - pMemObjInfo->pObjBindings.erase(it); - clearSucceeded = VK_TRUE; - break; - } - } - if (VK_FALSE == clearSucceeded) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT, - "MEM", "While trying to clear mem binding for %s obj %#" PRIxLEAST64 - ", unable to find that object referenced by mem obj %#" PRIxLEAST64, - object_type_to_string(type), handle, (uint64_t)pMemObjInfo->mem); - } - } - } - return skipCall; -} - -// For NULL mem case, output warning -// Make sure given object is in global object map -// IF a previous binding existed, output validation error -// Otherwise, add reference from objectInfo to memoryInfo -// Add reference off of objInfo -// device is required for error logging, need a dispatchable -// object for that. -static VkBool32 set_mem_binding(layer_data *my_data, void *dispatch_object, VkDeviceMemory mem, uint64_t handle, - VkDebugReportObjectTypeEXT type, const char *apiName) { - VkBool32 skipCall = VK_FALSE; - // Handle NULL case separately, just clear previous binding & decrement reference - if (mem == VK_NULL_HANDLE) { - // TODO: Verify against Valid Use section of spec. - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_MEM_OBJ, - "MEM", "In %s, attempting to Bind Obj(%#" PRIxLEAST64 ") to NULL", apiName, handle); - } else { - MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(my_data, handle, type); - if (!pObjBindInfo) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS, - "MEM", "In %s, attempting to update Binding of %s Obj(%#" PRIxLEAST64 ") that's not in global list()", - object_type_to_string(type), apiName, handle); - } else { - // non-null case so should have real mem obj - MT_MEM_OBJ_INFO *pMemInfo = get_mem_obj_info(my_data, mem); - if (pMemInfo) { - // TODO : Need to track mem binding for obj and report conflict here - MT_MEM_OBJ_INFO *pPrevBinding = get_mem_obj_info(my_data, pObjBindInfo->mem); - if (pPrevBinding != NULL) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, - (uint64_t)mem, __LINE__, MEMTRACK_REBIND_OBJECT, "MEM", - "In %s, attempting to bind memory (%#" PRIxLEAST64 ") to object (%#" PRIxLEAST64 - ") which has already been bound to mem object %#" PRIxLEAST64, - apiName, (uint64_t)mem, handle, (uint64_t)pPrevBinding->mem); - } else { - MT_OBJ_HANDLE_TYPE oht; - oht.handle = handle; - oht.type = type; - pMemInfo->pObjBindings.push_front(oht); - pMemInfo->refCount++; - // For image objects, make sure default memory state is correctly set - // TODO : What's the best/correct way to handle this? - if (VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT == type) { - VkImageCreateInfo ici = pObjBindInfo->create_info.image; - if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - // TODO:: More memory state transition stuff. - } - } - pObjBindInfo->mem = mem; - } - } - } - } - return skipCall; -} - -// For NULL mem case, clear any previous binding Else... -// Make sure given object is in its object map -// IF a previous binding existed, update binding -// Add reference from objectInfo to memoryInfo -// Add reference off of object's binding info -// Return VK_TRUE if addition is successful, VK_FALSE otherwise -static VkBool32 set_sparse_mem_binding(layer_data *my_data, void *dispObject, VkDeviceMemory mem, uint64_t handle, - VkDebugReportObjectTypeEXT type, const char *apiName) { - VkBool32 skipCall = VK_FALSE; - // Handle NULL case separately, just clear previous binding & decrement reference - if (mem == VK_NULL_HANDLE) { - skipCall = clear_object_binding(my_data, dispObject, handle, type); - } else { - MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(my_data, handle, type); - if (!pObjBindInfo) { - skipCall |= log_msg( - my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS, "MEM", - "In %s, attempting to update Binding of Obj(%#" PRIxLEAST64 ") that's not in global list()", apiName, handle); - } - // non-null case so should have real mem obj - MT_MEM_OBJ_INFO *pInfo = get_mem_obj_info(my_data, mem); - if (pInfo) { - // Search for object in memory object's binding list - VkBool32 found = VK_FALSE; - if (pInfo->pObjBindings.size() > 0) { - for (auto it = pInfo->pObjBindings.begin(); it != pInfo->pObjBindings.end(); ++it) { - if (((*it).handle == handle) && ((*it).type == type)) { - found = VK_TRUE; - break; - } - } - } - // If not present, add to list - if (found == VK_FALSE) { - MT_OBJ_HANDLE_TYPE oht; - oht.handle = handle; - oht.type = type; - pInfo->pObjBindings.push_front(oht); - pInfo->refCount++; - } - // Need to set mem binding for this object - pObjBindInfo->mem = mem; - } - } - return skipCall; -} - -template <typename T> -void print_object_map_members(layer_data *my_data, void *dispObj, T const &objectName, VkDebugReportObjectTypeEXT objectType, - const char *objectStr) { - for (auto const &element : objectName) { - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objectType, 0, __LINE__, MEMTRACK_NONE, "MEM", - " %s Object list contains %s Object %#" PRIxLEAST64 " ", objectStr, objectStr, element.first); - } -} - -// For given Object, get 'mem' obj that it's bound to or NULL if no binding -static VkBool32 get_mem_binding_from_object(layer_data *my_data, void *dispObj, const uint64_t handle, - const VkDebugReportObjectTypeEXT type, VkDeviceMemory *mem) { - VkBool32 skipCall = VK_FALSE; - *mem = VK_NULL_HANDLE; - MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(my_data, handle, type); - if (pObjBindInfo) { - if (pObjBindInfo->mem) { - *mem = pObjBindInfo->mem; - } else { - skipCall = - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS, - "MEM", "Trying to get mem binding for object %#" PRIxLEAST64 " but object has no mem binding", handle); - } - } else { - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT, - "MEM", "Trying to get mem binding for object %#" PRIxLEAST64 " but no such object in %s list", handle, - object_type_to_string(type)); - } - return skipCall; -} - -// Print details of MemObjInfo list -static void print_mem_list(layer_data *my_data, void *dispObj) { - MT_MEM_OBJ_INFO *pInfo = NULL; - - // Early out if info is not requested - if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) { - return; - } - - // Just printing each msg individually for now, may want to package these into single large print - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, - MEMTRACK_NONE, "MEM", "Details of Memory Object list (of size " PRINTF_SIZE_T_SPECIFIER " elements)", - my_data->memObjMap.size()); - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, - MEMTRACK_NONE, "MEM", "============================="); - - if (my_data->memObjMap.size() <= 0) - return; - - for (auto ii = my_data->memObjMap.begin(); ii != my_data->memObjMap.end(); ++ii) { - pInfo = &(*ii).second; - - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, - __LINE__, MEMTRACK_NONE, "MEM", " ===MemObjInfo at %p===", (void *)pInfo); - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, - __LINE__, MEMTRACK_NONE, "MEM", " Mem object: %#" PRIxLEAST64, (uint64_t)(pInfo->mem)); - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, - __LINE__, MEMTRACK_NONE, "MEM", " Ref Count: %u", pInfo->refCount); - if (0 != pInfo->allocInfo.allocationSize) { - string pAllocInfoMsg = vk_print_vkmemoryallocateinfo(&pInfo->allocInfo, "MEM(INFO): "); - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, - __LINE__, MEMTRACK_NONE, "MEM", " Mem Alloc info:\n%s", pAllocInfoMsg.c_str()); - } else { - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, - __LINE__, MEMTRACK_NONE, "MEM", " Mem Alloc info is NULL (alloc done by vkCreateSwapchainKHR())"); - } - - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, - __LINE__, MEMTRACK_NONE, "MEM", " VK OBJECT Binding list of size " PRINTF_SIZE_T_SPECIFIER " elements:", - pInfo->pObjBindings.size()); - if (pInfo->pObjBindings.size() > 0) { - for (list<MT_OBJ_HANDLE_TYPE>::iterator it = pInfo->pObjBindings.begin(); it != pInfo->pObjBindings.end(); ++it) { - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, - __LINE__, MEMTRACK_NONE, "MEM", " VK OBJECT %" PRIu64, it->handle); - } - } - - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, - __LINE__, MEMTRACK_NONE, "MEM", - " VK Command Buffer (CB) binding list of size " PRINTF_SIZE_T_SPECIFIER " elements", - pInfo->pCommandBufferBindings.size()); - if (pInfo->pCommandBufferBindings.size() > 0) { - for (list<VkCommandBuffer>::iterator it = pInfo->pCommandBufferBindings.begin(); - it != pInfo->pCommandBufferBindings.end(); ++it) { - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, - __LINE__, MEMTRACK_NONE, "MEM", " VK CB %p", (*it)); - } - } - } -} - -static void printCBList(layer_data *my_data, void *dispObj) { - MT_CB_INFO *pCBInfo = NULL; - - // Early out if info is not requested - if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) { - return; - } - - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, - MEMTRACK_NONE, "MEM", "Details of CB list (of size " PRINTF_SIZE_T_SPECIFIER " elements)", my_data->cbMap.size()); - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__, - MEMTRACK_NONE, "MEM", "=================="); - - if (my_data->cbMap.size() <= 0) - return; - - for (auto ii = my_data->cbMap.begin(); ii != my_data->cbMap.end(); ++ii) { - pCBInfo = &(*ii).second; - - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, - __LINE__, MEMTRACK_NONE, "MEM", " CB Info (%p) has CB %p, fenceId %" PRIx64 ", and fence %#" PRIxLEAST64, - (void *)pCBInfo, (void *)pCBInfo->commandBuffer, pCBInfo->fenceId, (uint64_t)pCBInfo->lastSubmittedFence); - - if (pCBInfo->pMemObjList.size() <= 0) - continue; - for (list<VkDeviceMemory>::iterator it = pCBInfo->pMemObjList.begin(); it != pCBInfo->pMemObjList.end(); ++it) { - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, - __LINE__, MEMTRACK_NONE, "MEM", " Mem obj %" PRIu64, (uint64_t)(*it)); - } - } -} - -static void init_mem_tracker(layer_data *my_data, const VkAllocationCallbacks *pAllocator) { - uint32_t report_flags = 0; - uint32_t debug_action = 0; - FILE *log_output = NULL; - const char *option_str; - VkDebugReportCallbackEXT callback; - // initialize mem_tracker options - report_flags = getLayerOptionFlags("lunarg_mem_tracker.report_flags", 0); - getLayerOptionEnum("lunarg_mem_tracker.debug_action", (uint32_t *)&debug_action); - - if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG) { - option_str = getLayerOption("lunarg_mem_tracker.log_filename"); - log_output = getLayerLogOutput(option_str, "lunarg_mem_tracker"); - VkDebugReportCallbackCreateInfoEXT dbgInfo; - memset(&dbgInfo, 0, sizeof(dbgInfo)); - dbgInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; - dbgInfo.pfnCallback = log_callback; - dbgInfo.pUserData = log_output; - dbgInfo.flags = report_flags; - layer_create_msg_callback(my_data->report_data, &dbgInfo, pAllocator, &callback); - my_data->logging_callback.push_back(callback); - } - - if (debug_action & VK_DBG_LAYER_ACTION_DEBUG_OUTPUT) { - VkDebugReportCallbackCreateInfoEXT dbgInfo; - memset(&dbgInfo, 0, sizeof(dbgInfo)); - dbgInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; - dbgInfo.pfnCallback = win32_debug_output_msg; - dbgInfo.pUserData = log_output; - dbgInfo.flags = report_flags; - layer_create_msg_callback(my_data->report_data, &dbgInfo, pAllocator, &callback); - my_data->logging_callback.push_back(callback); - } - - if (!globalLockInitialized) { - loader_platform_thread_create_mutex(&globalLock); - globalLockInitialized = 1; - } - - // Zero out memory property data - memset(&memProps, 0, sizeof(VkPhysicalDeviceMemoryProperties)); -} - -// hook DestroyInstance to remove tableInstanceMap entry -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) { - // Grab the key before the instance is destroyed. - dispatch_key key = get_dispatch_key(instance); - layer_data *my_data = get_my_data_ptr(key, layer_data_map); - VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; - pTable->DestroyInstance(instance, pAllocator); - - loader_platform_thread_lock_mutex(&globalLock); - // Clean up logging callback, if any - while (my_data->logging_callback.size() > 0) { - VkDebugReportCallbackEXT callback = my_data->logging_callback.back(); - layer_destroy_msg_callback(my_data->report_data, callback, pAllocator); - my_data->logging_callback.pop_back(); - } - - layer_debug_report_destroy_instance(my_data->report_data); - delete my_data->instance_dispatch_table; - layer_data_map.erase(key); - loader_platform_thread_unlock_mutex(&globalLock); - if (layer_data_map.empty()) { - // Release mutex when destroying last instance - loader_platform_thread_delete_mutex(&globalLock); - globalLockInitialized = 0; - } -} - -VKAPI_ATTR VkResult VKAPI_CALL -vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) { - VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); - - assert(chain_info->u.pLayerInfo); - PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; - PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance"); - if (fpCreateInstance == NULL) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - // Advance the link info for the next element on the chain - chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; - - VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance); - if (result != VK_SUCCESS) { - return result; - } - - layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map); - my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable; - layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr); - - my_data->report_data = debug_report_create_instance(my_data->instance_dispatch_table, *pInstance, - pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames); - - init_mem_tracker(my_data, pAllocator); - - return result; -} - -static void createDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) { - layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkLayerDispatchTable *pDisp = my_device_data->device_dispatch_table; - PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr; - pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpa(device, "vkCreateSwapchainKHR"); - pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)gpa(device, "vkDestroySwapchainKHR"); - pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)gpa(device, "vkGetSwapchainImagesKHR"); - pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)gpa(device, "vkAcquireNextImageKHR"); - pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR)gpa(device, "vkQueuePresentKHR"); - my_device_data->wsi_enabled = VK_FALSE; - for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { - if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) - my_device_data->wsi_enabled = true; - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) { - VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); - - assert(chain_info->u.pLayerInfo); - PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; - PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr; - PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice"); - if (fpCreateDevice == NULL) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - // Advance the link info for the next element on the chain - chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; - - VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice); - if (result != VK_SUCCESS) { - return result; - } - - layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map); - layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map); - - // Setup device dispatch table - my_device_data->device_dispatch_table = new VkLayerDispatchTable; - layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr); - - my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice); - createDeviceRegisterExtensions(pCreateInfo, *pDevice); - my_instance_data->instance_dispatch_table->GetPhysicalDeviceProperties(gpu, &my_device_data->properties); - - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) { - dispatch_key key = get_dispatch_key(device); - layer_data *my_device_data = get_my_data_ptr(key, layer_data_map); - VkBool32 skipCall = VK_FALSE; - loader_platform_thread_lock_mutex(&globalLock); - log_msg(my_device_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "Printing List details prior to vkDestroyDevice()"); - log_msg(my_device_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, - (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "================================================"); - print_mem_list(my_device_data, device); - printCBList(my_device_data, device); - skipCall = delete_cmd_buf_info_list(my_device_data); - // Report any memory leaks - MT_MEM_OBJ_INFO *pInfo = NULL; - if (my_device_data->memObjMap.size() > 0) { - for (auto ii = my_device_data->memObjMap.begin(); ii != my_device_data->memObjMap.end(); ++ii) { - pInfo = &(*ii).second; - if (pInfo->allocInfo.allocationSize != 0) { - // Valid Usage: All child objects created on device must have been destroyed prior to destroying device - skipCall |= - log_msg(my_device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pInfo->mem, __LINE__, MEMTRACK_MEMORY_LEAK, - "MEM", "Mem Object %" PRIu64 " has not been freed. You should clean up this memory by calling " - "vkFreeMemory(%" PRIu64 ") prior to vkDestroyDevice().", - (uint64_t)(pInfo->mem), (uint64_t)(pInfo->mem)); - } - } - } - // Queues persist until device is destroyed - delete_queue_info_list(my_device_data); - layer_debug_report_destroy_device(device); - loader_platform_thread_unlock_mutex(&globalLock); - -#if DISPATCH_MAP_DEBUG - fprintf(stderr, "Device: %p, key: %p\n", device, key); -#endif - VkLayerDispatchTable *pDisp = my_device_data->device_dispatch_table; - if (VK_FALSE == skipCall) { - pDisp->DestroyDevice(device, pAllocator); - } - delete my_device_data->device_dispatch_table; - layer_data_map.erase(key); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map); - VkLayerInstanceDispatchTable *pInstanceTable = my_data->instance_dispatch_table; - pInstanceTable->GetPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties); - memcpy(&memProps, pMemoryProperties, sizeof(VkPhysicalDeviceMemoryProperties)); -} - -static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}}; - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties) { - return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties); -} - -static const VkLayerProperties mtGlobalLayers[] = {{ - "VK_LAYER_LUNARG_mem_tracker", VK_API_VERSION, 1, "LunarG Validation Layer", -}}; - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) { - return util_GetLayerProperties(ARRAY_SIZE(mtGlobalLayers), mtGlobalLayers, pCount, pProperties); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, - const char *pLayerName, uint32_t *pCount, - VkExtensionProperties *pProperties) { - /* Mem tracker does not have any physical device extensions */ - if (pLayerName == NULL) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map); - VkLayerInstanceDispatchTable *pInstanceTable = my_data->instance_dispatch_table; - return pInstanceTable->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties); - } else { - return util_GetExtensionProperties(0, NULL, pCount, pProperties); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties) { - /* Mem tracker's physical device layers are the same as global */ - return util_GetLayerProperties(ARRAY_SIZE(mtGlobalLayers), mtGlobalLayers, pCount, pProperties); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkGetDeviceQueue(VkDevice device, uint32_t queueNodeIndex, uint32_t queueIndex, VkQueue *pQueue) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - my_data->device_dispatch_table->GetDeviceQueue(device, queueNodeIndex, queueIndex, pQueue); - loader_platform_thread_lock_mutex(&globalLock); - add_queue_info(my_data, *pQueue); - loader_platform_thread_unlock_mutex(&globalLock); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - - loader_platform_thread_lock_mutex(&globalLock); - // TODO : Need to track fence and clear mem references when fence clears - MT_CB_INFO *pCBInfo = NULL; - uint64_t fenceId = 0; - VkBool32 skipCall = add_fence_info(my_data, fence, queue, &fenceId); - - print_mem_list(my_data, queue); - printCBList(my_data, queue); - for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { - const VkSubmitInfo *submit = &pSubmits[submit_idx]; - for (uint32_t i = 0; i < submit->commandBufferCount; i++) { - pCBInfo = get_cmd_buf_info(my_data, submit->pCommandBuffers[i]); - if (pCBInfo) { - pCBInfo->fenceId = fenceId; - pCBInfo->lastSubmittedFence = fence; - pCBInfo->lastSubmittedQueue = queue; - for (auto &function : pCBInfo->validate_functions) { - skipCall |= function(); - } - } - } - - for (uint32_t i = 0; i < submit->waitSemaphoreCount; i++) { - VkSemaphore sem = submit->pWaitSemaphores[i]; - - if (my_data->semaphoreMap.find(sem) != my_data->semaphoreMap.end()) { - if (my_data->semaphoreMap[sem] != MEMTRACK_SEMAPHORE_STATE_SIGNALLED) { - skipCall = - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, - (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE", - "vkQueueSubmit: Semaphore must be in signaled state before passing to pWaitSemaphores"); - } - my_data->semaphoreMap[sem] = MEMTRACK_SEMAPHORE_STATE_WAIT; - } - } - for (uint32_t i = 0; i < submit->signalSemaphoreCount; i++) { - VkSemaphore sem = submit->pSignalSemaphores[i]; - - if (my_data->semaphoreMap.find(sem) != my_data->semaphoreMap.end()) { - if (my_data->semaphoreMap[sem] != MEMTRACK_SEMAPHORE_STATE_UNSET) { - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, (uint64_t)sem, __LINE__, MEMTRACK_NONE, - "SEMAPHORE", "vkQueueSubmit: Semaphore must not be currently signaled or in a wait state"); - } - my_data->semaphoreMap[sem] = MEMTRACK_SEMAPHORE_STATE_SIGNALLED; - } - } - } - - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->QueueSubmit(queue, submitCount, pSubmits, fence); - } - - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { - const VkSubmitInfo *submit = &pSubmits[submit_idx]; - for (uint32_t i = 0; i < submit->waitSemaphoreCount; i++) { - VkSemaphore sem = submit->pWaitSemaphores[i]; - - if (my_data->semaphoreMap.find(sem) != my_data->semaphoreMap.end()) { - my_data->semaphoreMap[sem] = MEMTRACK_SEMAPHORE_STATE_UNSET; - } - } - } - loader_platform_thread_unlock_mutex(&globalLock); - - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, - const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->AllocateMemory(device, pAllocateInfo, pAllocator, pMemory); - // TODO : Track allocations and overall size here - loader_platform_thread_lock_mutex(&globalLock); - add_mem_obj_info(my_data, device, *pMemory, pAllocateInfo); - print_mem_list(my_data, device); - loader_platform_thread_unlock_mutex(&globalLock); - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkFreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - my_data->bufferRanges.erase(mem); - my_data->imageRanges.erase(mem); - - // From spec : A memory object is freed by calling vkFreeMemory() when it is no longer needed. - // Before freeing a memory object, an application must ensure the memory object is no longer - // in use by the device—for example by command buffers queued for execution. The memory need - // not yet be unbound from all images and buffers, but any further use of those images or - // buffers (on host or device) for anything other than destroying those objects will result in - // undefined behavior. - - loader_platform_thread_lock_mutex(&globalLock); - freeMemObjInfo(my_data, device, mem, VK_FALSE); - print_mem_list(my_data, device); - printCBList(my_data, device); - loader_platform_thread_unlock_mutex(&globalLock); - my_data->device_dispatch_table->FreeMemory(device, mem, pAllocator); -} - -VkBool32 validateMemRange(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) { - VkBool32 skipCall = VK_FALSE; - - if (size == 0) { - // TODO: a size of 0 is not listed as an invalid use in the spec, should it be? - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, - (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM", - "VkMapMemory: Attempting to map memory range of size zero"); - } - - auto mem_element = my_data->memObjMap.find(mem); - if (mem_element != my_data->memObjMap.end()) { - // It is an application error to call VkMapMemory on an object that is already mapped - if (mem_element->second.memRange.size != 0) { - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, - (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM", - "VkMapMemory: Attempting to map memory on an already-mapped object %#" PRIxLEAST64, (uint64_t)mem); - } - - // Validate that offset + size is within object's allocationSize - if (size == VK_WHOLE_SIZE) { - if (offset >= mem_element->second.allocInfo.allocationSize) { - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, - "MEM", "Mapping Memory from %" PRIu64 " to %" PRIu64 " with total array size %" PRIu64, offset, - mem_element->second.allocInfo.allocationSize, mem_element->second.allocInfo.allocationSize); - } - } else { - if ((offset + size) > mem_element->second.allocInfo.allocationSize) { - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, - "MEM", "Mapping Memory from %" PRIu64 " to %" PRIu64 " with total array size %" PRIu64, offset, - size + offset, mem_element->second.allocInfo.allocationSize); - } - } - } - return skipCall; -} - -void storeMemRanges(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) { - auto mem_element = my_data->memObjMap.find(mem); - if (mem_element != my_data->memObjMap.end()) { - MemRange new_range; - new_range.offset = offset; - new_range.size = size; - mem_element->second.memRange = new_range; - } -} - -VkBool32 deleteMemRanges(layer_data *my_data, VkDeviceMemory mem) { - VkBool32 skipCall = VK_FALSE; - auto mem_element = my_data->memObjMap.find(mem); - if (mem_element != my_data->memObjMap.end()) { - if (!mem_element->second.memRange.size) { - // Valid Usage: memory must currently be mapped - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, - (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM", - "Unmapping Memory without memory being mapped: mem obj %#" PRIxLEAST64, (uint64_t)mem); - } - mem_element->second.memRange.size = 0; - if (mem_element->second.pData) { - free(mem_element->second.pData); - mem_element->second.pData = 0; - } - } - return skipCall; -} - -static char NoncoherentMemoryFillValue = 0xb; - -void initializeAndTrackMemory(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize size, void **ppData) { - auto mem_element = my_data->memObjMap.find(mem); - if (mem_element != my_data->memObjMap.end()) { - mem_element->second.pDriverData = *ppData; - uint32_t index = mem_element->second.allocInfo.memoryTypeIndex; - if (memProps.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { - mem_element->second.pData = 0; - } else { - if (size == VK_WHOLE_SIZE) { - size = mem_element->second.allocInfo.allocationSize; - } - size_t convSize = (size_t)(size); - mem_element->second.pData = malloc(2 * convSize); - memset(mem_element->second.pData, NoncoherentMemoryFillValue, 2 * convSize); - *ppData = static_cast<char *>(mem_element->second.pData) + (convSize / 2); - } - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags, void **ppData) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkBool32 skipCall = VK_FALSE; - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - loader_platform_thread_lock_mutex(&globalLock); - MT_MEM_OBJ_INFO *pMemObj = get_mem_obj_info(my_data, mem); - if (pMemObj) { - pMemObj->valid = true; - if ((memProps.memoryTypes[pMemObj->allocInfo.memoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) { - skipCall = - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, - (uint64_t)mem, __LINE__, MEMTRACK_INVALID_STATE, "MEM", - "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj %#" PRIxLEAST64, (uint64_t)mem); - } - } - skipCall |= validateMemRange(my_data, mem, offset, size); - storeMemRanges(my_data, mem, offset, size); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->MapMemory(device, mem, offset, size, flags, ppData); - initializeAndTrackMemory(my_data, mem, size, ppData); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(VkDevice device, VkDeviceMemory mem) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkBool32 skipCall = VK_FALSE; - - loader_platform_thread_lock_mutex(&globalLock); - skipCall |= deleteMemRanges(my_data, mem); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->UnmapMemory(device, mem); - } -} - -VkBool32 validateMemoryIsMapped(layer_data *my_data, const char *funcName, uint32_t memRangeCount, - const VkMappedMemoryRange *pMemRanges) { - VkBool32 skipCall = VK_FALSE; - for (uint32_t i = 0; i < memRangeCount; ++i) { - auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory); - if (mem_element != my_data->memObjMap.end()) { - if (mem_element->second.memRange.offset > pMemRanges[i].offset) { - skipCall |= log_msg( - my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, - (uint64_t)pMemRanges[i].memory, __LINE__, MEMTRACK_INVALID_MAP, "MEM", - "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER ") is less than Memory Object's offset " - "(" PRINTF_SIZE_T_SPECIFIER ").", - funcName, static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(mem_element->second.memRange.offset)); - } - if ((mem_element->second.memRange.size != VK_WHOLE_SIZE) && - ((mem_element->second.memRange.offset + mem_element->second.memRange.size) < - (pMemRanges[i].offset + pMemRanges[i].size))) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__, - MEMTRACK_INVALID_MAP, "MEM", "%s: Flush/Invalidate upper-bound (" PRINTF_SIZE_T_SPECIFIER - ") exceeds the Memory Object's upper-bound " - "(" PRINTF_SIZE_T_SPECIFIER ").", - funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size), - static_cast<size_t>(mem_element->second.memRange.offset + mem_element->second.memRange.size)); - } - } - } - return skipCall; -} - -VkBool32 validateAndCopyNoncoherentMemoryToDriver(layer_data *my_data, uint32_t memRangeCount, - const VkMappedMemoryRange *pMemRanges) { - VkBool32 skipCall = VK_FALSE; - for (uint32_t i = 0; i < memRangeCount; ++i) { - auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory); - if (mem_element != my_data->memObjMap.end()) { - if (mem_element->second.pData) { - VkDeviceSize size = mem_element->second.memRange.size; - VkDeviceSize half_size = (size / 2); - char *data = static_cast<char *>(mem_element->second.pData); - for (auto j = 0; j < half_size; ++j) { - if (data[j] != NoncoherentMemoryFillValue) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__, - MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj %" PRIxLEAST64, - (uint64_t)pMemRanges[i].memory); - } - } - for (auto j = size + half_size; j < 2 * size; ++j) { - if (data[j] != NoncoherentMemoryFillValue) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__, - MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj %" PRIxLEAST64, - (uint64_t)pMemRanges[i].memory); - } - } - memcpy(mem_element->second.pDriverData, static_cast<void *>(data + (size_t)(half_size)), (size_t)(size)); - } - } - } - return skipCall; -} - -VK_LAYER_EXPORT VkResult VKAPI_CALL -vkFlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) { - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - VkBool32 skipCall = VK_FALSE; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - - loader_platform_thread_lock_mutex(&globalLock); - skipCall |= validateAndCopyNoncoherentMemoryToDriver(my_data, memRangeCount, pMemRanges); - skipCall |= validateMemoryIsMapped(my_data, "vkFlushMappedMemoryRanges", memRangeCount, pMemRanges); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->FlushMappedMemoryRanges(device, memRangeCount, pMemRanges); - } - return result; -} - -VK_LAYER_EXPORT VkResult VKAPI_CALL -vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) { - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - VkBool32 skipCall = VK_FALSE; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - - loader_platform_thread_lock_mutex(&globalLock); - skipCall |= validateMemoryIsMapped(my_data, "vkInvalidateMappedMemoryRanges", memRangeCount, pMemRanges); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - delete_fence_info(my_data, fence); - auto item = my_data->fenceMap.find(fence); - if (item != my_data->fenceMap.end()) { - my_data->fenceMap.erase(item); - } - loader_platform_thread_unlock_mutex(&globalLock); - my_data->device_dispatch_table->DestroyFence(device, fence, pAllocator); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkBool32 skipCall = VK_FALSE; - loader_platform_thread_lock_mutex(&globalLock); - auto item = my_data->bufferMap.find((uint64_t)buffer); - if (item != my_data->bufferMap.end()) { - skipCall = clear_object_binding(my_data, device, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT); - my_data->bufferMap.erase(item); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->DestroyBuffer(device, buffer, pAllocator); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkBool32 skipCall = VK_FALSE; - loader_platform_thread_lock_mutex(&globalLock); - auto item = my_data->imageMap.find((uint64_t)image); - if (item != my_data->imageMap.end()) { - skipCall = clear_object_binding(my_data, device, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); - my_data->imageMap.erase(item); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->DestroyImage(device, image, pAllocator); - } -} - -VkBool32 print_memory_range_error(layer_data *my_data, const uint64_t object_handle, const uint64_t other_handle, - VkDebugReportObjectTypeEXT object_type) { - if (object_type == VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT) { - return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0, - MEMTRACK_INVALID_ALIASING, "MEM", "Buffer %" PRIx64 " is alised with image %" PRIx64, object_handle, - other_handle); - } else { - return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0, - MEMTRACK_INVALID_ALIASING, "MEM", "Image %" PRIx64 " is alised with buffer %" PRIx64, object_handle, - other_handle); - } -} - -VkBool32 validate_memory_range(layer_data *my_data, const unordered_map<VkDeviceMemory, vector<MEMORY_RANGE>> &memory, - const MEMORY_RANGE &new_range, VkDebugReportObjectTypeEXT object_type) { - VkBool32 skip_call = false; - if (!memory.count(new_range.memory)) - return false; - const vector<MEMORY_RANGE> &ranges = memory.at(new_range.memory); - for (auto range : ranges) { - if ((range.end & ~(my_data->properties.limits.bufferImageGranularity - 1)) < - (new_range.start & ~(my_data->properties.limits.bufferImageGranularity - 1))) - continue; - if ((range.start & ~(my_data->properties.limits.bufferImageGranularity - 1)) > - (new_range.end & ~(my_data->properties.limits.bufferImageGranularity - 1))) - continue; - skip_call |= print_memory_range_error(my_data, new_range.handle, range.handle, object_type); - } - return skip_call; -} - -VkBool32 validate_buffer_image_aliasing(layer_data *my_data, uint64_t handle, VkDeviceMemory mem, VkDeviceSize memoryOffset, - VkMemoryRequirements memRequirements, - unordered_map<VkDeviceMemory, vector<MEMORY_RANGE>> &ranges, - const unordered_map<VkDeviceMemory, vector<MEMORY_RANGE>> &other_ranges, - VkDebugReportObjectTypeEXT object_type) { - MEMORY_RANGE range; - range.handle = handle; - range.memory = mem; - range.start = memoryOffset; - range.end = memoryOffset + memRequirements.size - 1; - ranges[mem].push_back(range); - return validate_memory_range(my_data, other_ranges, range, object_type); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - loader_platform_thread_lock_mutex(&globalLock); - // Track objects tied to memory - uint64_t buffer_handle = (uint64_t)(buffer); - VkBool32 skipCall = - set_mem_binding(my_data, device, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory"); - add_object_binding_info(my_data, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, mem); - { - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(device, buffer, &memRequirements); - skipCall |= - validate_buffer_image_aliasing(my_data, buffer_handle, mem, memoryOffset, memRequirements, my_data->bufferRanges, - my_data->imageRanges, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT); - } - print_mem_list(my_data, device); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->BindBufferMemory(device, buffer, mem, memoryOffset); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - loader_platform_thread_lock_mutex(&globalLock); - // Track objects tied to memory - uint64_t image_handle = (uint64_t)(image); - VkBool32 skipCall = - set_mem_binding(my_data, device, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory"); - add_object_binding_info(my_data, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, mem); - { - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(device, image, &memRequirements); - skipCall |= validate_buffer_image_aliasing(my_data, image_handle, mem, memoryOffset, memRequirements, my_data->imageRanges, - my_data->bufferRanges, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); - } - print_mem_list(my_data, device); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->BindImageMemory(device, image, mem, memoryOffset); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - // TODO : What to track here? - // Could potentially save returned mem requirements and validate values passed into BindBufferMemory - my_data->device_dispatch_table->GetBufferMemoryRequirements(device, buffer, pMemoryRequirements); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - // TODO : What to track here? - // Could potentially save returned mem requirements and validate values passed into BindImageMemory - my_data->device_dispatch_table->GetImageMemoryRequirements(device, image, pMemoryRequirements); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - VkBool32 skipCall = VK_FALSE; - - loader_platform_thread_lock_mutex(&globalLock); - - for (uint32_t i = 0; i < bindInfoCount; i++) { - const VkBindSparseInfo *bindInfo = &pBindInfo[i]; - // Track objects tied to memory - for (uint32_t j = 0; j < bindInfo->bufferBindCount; j++) { - for (uint32_t k = 0; k < bindInfo->pBufferBinds[j].bindCount; k++) { - if (set_sparse_mem_binding(my_data, queue, bindInfo->pBufferBinds[j].pBinds[k].memory, - (uint64_t)bindInfo->pBufferBinds[j].buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, - "vkQueueBindSparse")) - skipCall = VK_TRUE; - } - } - for (uint32_t j = 0; j < bindInfo->imageOpaqueBindCount; j++) { - for (uint32_t k = 0; k < bindInfo->pImageOpaqueBinds[j].bindCount; k++) { - if (set_sparse_mem_binding(my_data, queue, bindInfo->pImageOpaqueBinds[j].pBinds[k].memory, - (uint64_t)bindInfo->pImageOpaqueBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - "vkQueueBindSparse")) - skipCall = VK_TRUE; - } - } - for (uint32_t j = 0; j < bindInfo->imageBindCount; j++) { - for (uint32_t k = 0; k < bindInfo->pImageBinds[j].bindCount; k++) { - if (set_sparse_mem_binding(my_data, queue, bindInfo->pImageBinds[j].pBinds[k].memory, - (uint64_t)bindInfo->pImageBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - "vkQueueBindSparse")) - skipCall = VK_TRUE; - } - } - // Validate semaphore state - for (uint32_t i = 0; i < bindInfo->waitSemaphoreCount; i++) { - VkSemaphore sem = bindInfo->pWaitSemaphores[i]; - - if (my_data->semaphoreMap.find(sem) != my_data->semaphoreMap.end()) { - if (my_data->semaphoreMap[sem] != MEMTRACK_SEMAPHORE_STATE_SIGNALLED) { - skipCall = - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, - (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE", - "vkQueueBindSparse: Semaphore must be in signaled state before passing to pWaitSemaphores"); - } - my_data->semaphoreMap[sem] = MEMTRACK_SEMAPHORE_STATE_WAIT; - } - } - for (uint32_t i = 0; i < bindInfo->signalSemaphoreCount; i++) { - VkSemaphore sem = bindInfo->pSignalSemaphores[i]; - - if (my_data->semaphoreMap.find(sem) != my_data->semaphoreMap.end()) { - if (my_data->semaphoreMap[sem] != MEMTRACK_SEMAPHORE_STATE_UNSET) { - skipCall = - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, - (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE", - "vkQueueBindSparse: Semaphore must not be currently signaled or in a wait state"); - } - my_data->semaphoreMap[sem] = MEMTRACK_SEMAPHORE_STATE_SIGNALLED; - } - } - } - - print_mem_list(my_data, queue); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence); - } - - // Update semaphore state - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t bind_info_idx = 0; bind_info_idx < bindInfoCount; bind_info_idx++) { - const VkBindSparseInfo *bindInfo = &pBindInfo[bind_info_idx]; - for (uint32_t i = 0; i < bindInfo->waitSemaphoreCount; i++) { - VkSemaphore sem = bindInfo->pWaitSemaphores[i]; - - if (my_data->semaphoreMap.find(sem) != my_data->semaphoreMap.end()) { - my_data->semaphoreMap[sem] = MEMTRACK_SEMAPHORE_STATE_UNSET; - } - } - } - loader_platform_thread_unlock_mutex(&globalLock); - - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->CreateFence(device, pCreateInfo, pAllocator, pFence); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - MT_FENCE_INFO *pFI = &my_data->fenceMap[*pFence]; - memset(pFI, 0, sizeof(MT_FENCE_INFO)); - memcpy(&(pFI->createInfo), pCreateInfo, sizeof(VkFenceCreateInfo)); - if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) { - pFI->firstTimeFlag = VK_TRUE; - } - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - VkBool32 skipCall = VK_FALSE; - - loader_platform_thread_lock_mutex(&globalLock); - // Reset fence state in fenceCreateInfo structure - for (uint32_t i = 0; i < fenceCount; i++) { - auto fence_item = my_data->fenceMap.find(pFences[i]); - if (fence_item != my_data->fenceMap.end()) { - // Validate fences in SIGNALED state - if (!(fence_item->second.createInfo.flags & VK_FENCE_CREATE_SIGNALED_BIT)) { - // TODO: I don't see a Valid Usage section for ResetFences. This behavior should be documented there. - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, - (uint64_t)pFences[i], __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", - "Fence %#" PRIxLEAST64 " submitted to VkResetFences in UNSIGNALED STATE", (uint64_t)pFences[i]); - } else { - fence_item->second.createInfo.flags = - static_cast<VkFenceCreateFlags>(fence_item->second.createInfo.flags & ~VK_FENCE_CREATE_SIGNALED_BIT); - } - } - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->ResetFences(device, fenceCount, pFences); - } - return result; -} - -static inline VkBool32 verifyFenceStatus(VkDevice device, VkFence fence, const char *apiCall) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkBool32 skipCall = VK_FALSE; - auto pFenceInfo = my_data->fenceMap.find(fence); - if (pFenceInfo != my_data->fenceMap.end()) { - if (pFenceInfo->second.firstTimeFlag != VK_TRUE) { - if ((pFenceInfo->second.createInfo.flags & VK_FENCE_CREATE_SIGNALED_BIT) && - pFenceInfo->second.firstTimeFlag != VK_TRUE) { - skipCall |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, - (uint64_t)fence, __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", - "%s specified fence %#" PRIxLEAST64 " already in SIGNALED state.", apiCall, (uint64_t)fence); - } - if (!pFenceInfo->second.queue && !pFenceInfo->second.swapchain) { // Checking status of unsubmitted fence - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, - reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM", - "%s called for fence %#" PRIxLEAST64 " which has not been submitted on a Queue or during " - "acquire next image.", - apiCall, reinterpret_cast<uint64_t &>(fence)); - } - } else { - pFenceInfo->second.firstTimeFlag = VK_FALSE; - } - } - return skipCall; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus(VkDevice device, VkFence fence) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - VkBool32 skipCall = verifyFenceStatus(device, fence, "vkGetFenceStatus"); - loader_platform_thread_unlock_mutex(&globalLock); - if (skipCall) - return VK_ERROR_VALIDATION_FAILED_EXT; - VkResult result = my_data->device_dispatch_table->GetFenceStatus(device, fence); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - update_fence_tracking(my_data, fence); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkBool32 skipCall = VK_FALSE; - // Verify fence status of submitted fences - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < fenceCount; i++) { - skipCall |= verifyFenceStatus(device, pFences[i], "vkWaitForFences"); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (skipCall) - return VK_ERROR_VALIDATION_FAILED_EXT; - VkResult result = my_data->device_dispatch_table->WaitForFences(device, fenceCount, pFences, waitAll, timeout); - - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - if (waitAll || fenceCount == 1) { // Clear all the fences - for (uint32_t i = 0; i < fenceCount; i++) { - update_fence_tracking(my_data, pFences[i]); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle(VkQueue queue) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); - VkResult result = my_data->device_dispatch_table->QueueWaitIdle(queue); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - retire_queue_fences(my_data, queue); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle(VkDevice device) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->DeviceWaitIdle(device); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - retire_device_fences(my_data, device); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->CreateBuffer(device, pCreateInfo, pAllocator, pBuffer); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - add_object_create_info(my_data, (uint64_t)*pBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, pCreateInfo); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage); - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - add_object_create_info(my_data, (uint64_t)*pImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, pCreateInfo); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkImageView *pView) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->CreateImageView(device, pCreateInfo, pAllocator, pView); - if (result == VK_SUCCESS) { - loader_platform_thread_lock_mutex(&globalLock); - my_data->imageViewMap[*pView].image = pCreateInfo->image; - // Validate that img has correct usage flags set - validate_image_usage_flags(my_data, device, pCreateInfo->image, - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - VK_FALSE, "vkCreateImageView()", "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT]_BIT"); - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkBufferView *pView) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->CreateBufferView(device, pCreateInfo, pAllocator, pView); - if (result == VK_SUCCESS) { - loader_platform_thread_lock_mutex(&globalLock); - // In order to create a valid buffer view, the buffer must have been created with at least one of the - // following flags: UNIFORM_TEXEL_BUFFER_BIT or STORAGE_TEXEL_BUFFER_BIT - validate_buffer_usage_flags(my_data, device, pCreateInfo->buffer, - VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, VK_FALSE, - "vkCreateBufferView()", "VK_BUFFER_USAGE_[STORAGE|UNIFORM]_TEXEL_BUFFER_BIT"); - my_data->bufferViewMap[*pView] = *pCreateInfo; - loader_platform_thread_unlock_mutex(&globalLock); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - my_data->device_dispatch_table->DestroyBufferView(device, bufferView, pAllocator); - loader_platform_thread_lock_mutex(&globalLock); - auto item = my_data->bufferViewMap.find(bufferView); - if (item != my_data->bufferViewMap.end()) { - my_data->bufferViewMap.erase(item); - } - loader_platform_thread_unlock_mutex(&globalLock); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo, VkCommandBuffer *pCommandBuffer) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer); - - loader_platform_thread_lock_mutex(&globalLock); - if (VK_SUCCESS == result) { - for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) { - add_cmd_buf_info(my_data, pCreateInfo->commandPool, pCommandBuffer[i]); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - printCBList(my_data, device); - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, - uint32_t commandBufferCount, - const VkCommandBuffer *pCommandBuffers) { - VkBool32 skipCall = VK_FALSE; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < commandBufferCount; i++) { - skipCall |= delete_cmd_buf_info(my_data, commandPool, pCommandBuffers[i]); - } - printCBList(my_data, device); - loader_platform_thread_unlock_mutex(&globalLock); - - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkCommandPool *pCommandPool) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool); - - loader_platform_thread_lock_mutex(&globalLock); - - // Add cmd pool to map - my_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags; - loader_platform_thread_unlock_mutex(&globalLock); - - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) { - VkBool32 commandBufferComplete = VK_FALSE; - VkBool32 skipCall = VK_FALSE; - // Verify that command buffers in pool are complete (not in-flight) - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - for (auto it = my_data->commandPoolMap[commandPool].pCommandBuffers.begin(); - it != my_data->commandPoolMap[commandPool].pCommandBuffers.end(); it++) { - commandBufferComplete = VK_FALSE; - skipCall = checkCBCompleted(my_data, *it, &commandBufferComplete); - if (VK_FALSE == commandBufferComplete) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)(*it), __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", - "Destroying Command Pool 0x%" PRIxLEAST64 " before " - "its command buffer (0x%" PRIxLEAST64 ") has completed.", - (uint64_t)(commandPool), reinterpret_cast<uint64_t>(*it)); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->DestroyCommandPool(device, commandPool, pAllocator); - } - - loader_platform_thread_lock_mutex(&globalLock); - auto item = my_data->commandPoolMap[commandPool].pCommandBuffers.begin(); - // Remove command buffers from command buffer map - while (item != my_data->commandPoolMap[commandPool].pCommandBuffers.end()) { - auto del_item = item++; - delete_cmd_buf_info(my_data, commandPool, *del_item); - } - my_data->commandPoolMap.erase(commandPool); - loader_platform_thread_unlock_mutex(&globalLock); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkBool32 commandBufferComplete = VK_FALSE; - VkBool32 skipCall = VK_FALSE; - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - - loader_platform_thread_lock_mutex(&globalLock); - auto it = my_data->commandPoolMap[commandPool].pCommandBuffers.begin(); - // Verify that CB's in pool are complete (not in-flight) - while (it != my_data->commandPoolMap[commandPool].pCommandBuffers.end()) { - skipCall = checkCBCompleted(my_data, (*it), &commandBufferComplete); - if (VK_FALSE == commandBufferComplete) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)(*it), __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", - "Resetting CB %p before it has completed. You must check CB " - "flag before calling vkResetCommandBuffer().", - (*it)); - } else { - // Clear memory references at this point. - skipCall |= clear_cmd_buf_and_mem_references(my_data, (*it)); - } - ++it; - } - loader_platform_thread_unlock_mutex(&globalLock); - - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->ResetCommandPool(device, commandPool, flags); - } - - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - VkBool32 skipCall = VK_FALSE; - VkBool32 commandBufferComplete = VK_FALSE; - loader_platform_thread_lock_mutex(&globalLock); - - // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references - skipCall = checkCBCompleted(my_data, commandBuffer, &commandBufferComplete); - - if (VK_FALSE == commandBufferComplete) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)commandBuffer, __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", - "Calling vkBeginCommandBuffer() on active CB %p before it has completed. " - "You must check CB flag before this call.", - commandBuffer); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->BeginCommandBuffer(commandBuffer, pBeginInfo); - } - loader_platform_thread_lock_mutex(&globalLock); - clear_cmd_buf_and_mem_references(my_data, commandBuffer); - loader_platform_thread_unlock_mutex(&globalLock); - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(VkCommandBuffer commandBuffer) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - // TODO : Anything to do here? - VkResult result = my_data->device_dispatch_table->EndCommandBuffer(commandBuffer); - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - VkBool32 skipCall = VK_FALSE; - VkBool32 commandBufferComplete = VK_FALSE; - loader_platform_thread_lock_mutex(&globalLock); - - // Verify that CB is complete (not in-flight) - skipCall = checkCBCompleted(my_data, commandBuffer, &commandBufferComplete); - if (VK_FALSE == commandBufferComplete) { - skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - (uint64_t)commandBuffer, __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", - "Resetting CB %p before it has completed. You must check CB " - "flag before calling vkResetCommandBuffer().", - commandBuffer); - } - // Clear memory references as this point. - skipCall |= clear_cmd_buf_and_mem_references(my_data, commandBuffer); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->ResetCommandBuffer(commandBuffer, flags); - } - return result; -} - -// TODO : For any vkCmdBind* calls that include an object which has mem bound to it, -// need to account for that mem now having binding to given commandBuffer -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); -#if 0 // FIXME: NEED TO FIX THE FOLLOWING CODE AND REMOVE THIS #if 0 - // TODO : If memory bound to pipeline, then need to tie that mem to commandBuffer - if (getPipeline(pipeline)) { - MT_CB_INFO *pCBInfo = get_cmd_buf_info(my_data, commandBuffer); - if (pCBInfo) { - pCBInfo->pipelines[pipelineBindPoint] = pipeline; - } - } - else { - "Attempt to bind Pipeline %p that doesn't exist!", (void*)pipeline); - layerCbMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, pipeline, __LINE__, MEMTRACK_INVALID_OBJECT, (char *) "DS", (char *) str); - } -#endif - my_data->device_dispatch_table->CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, - uint32_t firstSet, uint32_t setCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount, - const uint32_t *pDynamicOffsets) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - auto cb_data = my_data->cbMap.find(commandBuffer); - if (cb_data != my_data->cbMap.end()) { - std::vector<VkDescriptorSet> &activeDescriptorSets = cb_data->second.activeDescriptorSets; - if (activeDescriptorSets.size() < (setCount + firstSet)) { - activeDescriptorSets.resize(setCount + firstSet); - } - for (uint32_t i = 0; i < setCount; ++i) { - activeDescriptorSets[i + firstSet] = pDescriptorSets[i]; - } - } - // TODO : Somewhere need to verify that all textures referenced by shaders in DS are in some type of *SHADER_READ* state - my_data->device_dispatch_table->CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount, - pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, - uint32_t bindingCount, const VkBuffer *pBuffers, - const VkDeviceSize *pOffsets) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkBool32 skip_call = false; - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < bindingCount; ++i) { - VkDeviceMemory mem; - skip_call |= get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)(pBuffers[i]), - VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - auto cb_data = my_data->cbMap.find(commandBuffer); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = - [=]() { return validate_memory_is_valid(my_data, mem, "vkCmdBindVertexBuffers()"); }; - cb_data->second.validate_functions.push_back(function); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - // TODO : Somewhere need to verify that VBs have correct usage state flagged - if (!skip_call) - my_data->device_dispatch_table->CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - loader_platform_thread_lock_mutex(&globalLock); - VkBool32 skip_call = - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)(buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - auto cb_data = my_data->cbMap.find(commandBuffer); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(my_data, mem, "vkCmdBindIndexBuffer()"); }; - cb_data->second.validate_functions.push_back(function); - } - loader_platform_thread_unlock_mutex(&globalLock); - // TODO : Somewhere need to verify that IBs have correct usage state flagged - if (!skip_call) - my_data->device_dispatch_table->CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites, - uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - uint32_t j = 0; - for (uint32_t i = 0; i < descriptorWriteCount; ++i) { - if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) { - my_data->descriptorSetMap[pDescriptorWrites[i].dstSet].images.push_back( - pDescriptorWrites[i].pImageInfo[j].imageView); - } - } else if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { - for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) { - my_data->descriptorSetMap[pDescriptorWrites[i].dstSet].buffers.push_back( - my_data->bufferViewMap[pDescriptorWrites[i].pTexelBufferView[j]].buffer); - } - } else if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || - pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) { - for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) { - my_data->descriptorSetMap[pDescriptorWrites[i].dstSet].buffers.push_back( - pDescriptorWrites[i].pBufferInfo[j].buffer); - } - } - } - // TODO : Need to handle descriptor copies. Will wait on this until merge w/ - // draw_state - my_data->device_dispatch_table->UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, - pDescriptorCopies); -} - -bool markStoreImagesAndBuffersAsWritten(VkCommandBuffer commandBuffer) { - bool skip_call = false; - loader_platform_thread_lock_mutex(&globalLock); - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - auto cb_data = my_data->cbMap.find(commandBuffer); - if (cb_data == my_data->cbMap.end()) - return skip_call; - std::vector<VkDescriptorSet> &activeDescriptorSets = cb_data->second.activeDescriptorSets; - for (auto descriptorSet : activeDescriptorSets) { - auto ds_data = my_data->descriptorSetMap.find(descriptorSet); - if (ds_data == my_data->descriptorSetMap.end()) - continue; - std::vector<VkImageView> images = ds_data->second.images; - std::vector<VkBuffer> buffers = ds_data->second.buffers; - for (auto imageView : images) { - auto iv_data = my_data->imageViewMap.find(imageView); - if (iv_data == my_data->imageViewMap.end()) - continue; - VkImage image = iv_data->second.image; - VkDeviceMemory mem; - skip_call |= - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true, image); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - for (auto buffer : buffers) { - VkDeviceMemory mem; - skip_call |= - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - return skip_call; -} - -VKAPI_ATTR void VKAPI_CALL vkCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, - uint32_t firstVertex, uint32_t firstInstance) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - bool skip_call = markStoreImagesAndBuffersAsWritten(commandBuffer); - if (!skip_call) - my_data->device_dispatch_table->CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance); -} - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, - uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - bool skip_call = markStoreImagesAndBuffersAsWritten(commandBuffer); - if (!skip_call) - my_data->device_dispatch_table->CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, - firstInstance); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - loader_platform_thread_lock_mutex(&globalLock); - VkBool32 skipCall = - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdDrawIndirect"); - skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdDrawIndirect(commandBuffer, buffer, offset, count, stride); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - loader_platform_thread_lock_mutex(&globalLock); - VkBool32 skipCall = - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdDrawIndexedIndirect"); - skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride); - } -} - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - bool skip_call = markStoreImagesAndBuffersAsWritten(commandBuffer); - if (!skip_call) - my_data->device_dispatch_table->CmdDispatch(commandBuffer, x, y, z); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - loader_platform_thread_lock_mutex(&globalLock); - VkBool32 skipCall = - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdDispatchIndirect"); - skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdDispatchIndirect(commandBuffer, buffer, offset); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, - uint32_t regionCount, const VkBufferCopy *pRegions) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - VkBool32 skipCall = VK_FALSE; - auto cb_data = my_data->cbMap.find(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - skipCall = - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(my_data, mem, "vkCmdCopyBuffer()"); }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyBuffer"); - skipCall |= - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyBuffer"); - // Validate that SRC & DST buffers have correct usage flags set - skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, - "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT"); - skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, - "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, - VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize destStride, VkQueryResultFlags flags) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - VkBool32 skipCall = VK_FALSE; - auto cb_data = my_data->cbMap.find(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - skipCall |= - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyQueryPoolResults"); - // Validate that DST buffer has correct usage flags set - skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, - "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, - dstOffset, destStride, flags); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, - VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - VkBool32 skipCall = VK_FALSE; - auto cb_data = my_data->cbMap.find(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - // Validate that src & dst images have correct usage flags set - skipCall = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(my_data, mem, "vkCmdCopyImage()", srcImage); }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyImage"); - skipCall |= - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true, dstImage); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyImage"); - skipCall |= validate_image_usage_flags(my_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, - "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT"); - skipCall |= validate_image_usage_flags(my_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, - "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT"); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, - pRegions); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, - VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - VkBool32 skipCall = VK_FALSE; - auto cb_data = my_data->cbMap.find(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - // Validate that src & dst images have correct usage flags set - skipCall = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(my_data, mem, "vkCmdBlitImage()", srcImage); }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdBlitImage"); - skipCall |= - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true, dstImage); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdBlitImage"); - skipCall |= validate_image_usage_flags(my_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, - "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT"); - skipCall |= validate_image_usage_flags(my_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, - "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT"); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, - pRegions, filter); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, - VkImage dstImage, VkImageLayout dstImageLayout, - uint32_t regionCount, const VkBufferImageCopy *pRegions) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - VkBool32 skipCall = VK_FALSE; - auto cb_data = my_data->cbMap.find(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - skipCall = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true, dstImage); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyBufferToImage"); - skipCall |= - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(my_data, mem, "vkCmdCopyBufferToImage()"); }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyBufferToImage"); - // Validate that src buff & dst image have correct usage flags set - skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, - "vkCmdCopyBufferToImage()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT"); - skipCall |= validate_image_usage_flags(my_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, - "vkCmdCopyBufferToImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT"); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, - pRegions); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, - VkImageLayout srcImageLayout, VkBuffer dstBuffer, - uint32_t regionCount, const VkBufferImageCopy *pRegions) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - VkBool32 skipCall = VK_FALSE; - auto cb_data = my_data->cbMap.find(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - skipCall = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = - [=]() { return validate_memory_is_valid(my_data, mem, "vkCmdCopyImageToBuffer()", srcImage); }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyImageToBuffer"); - skipCall |= - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyImageToBuffer"); - // Validate that dst buff & src image have correct usage flags set - skipCall |= validate_image_usage_flags(my_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, - "vkCmdCopyImageToBuffer()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT"); - skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, - "vkCmdCopyImageToBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, - pRegions); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, - VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t *pData) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - VkBool32 skipCall = VK_FALSE; - auto cb_data = my_data->cbMap.find(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - skipCall = - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdUpdateBuffer"); - // Validate that dst buff has correct usage flags set - skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, - "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkDeviceMemory mem; - VkBool32 skipCall = VK_FALSE; - auto cb_data = my_data->cbMap.find(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - skipCall = - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdFillBuffer"); - // Validate that dst buff has correct usage flags set - skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, - "vkCmdFillBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT"); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, - VkImageLayout imageLayout, const VkClearColorValue *pColor, - uint32_t rangeCount, const VkImageSubresourceRange *pRanges) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state - VkDeviceMemory mem; - VkBool32 skipCall = VK_FALSE; - auto cb_data = my_data->cbMap.find(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - skipCall = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true, image); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdClearColorImage"); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, - const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount, - const VkImageSubresourceRange *pRanges) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state - VkDeviceMemory mem; - VkBool32 skipCall = VK_FALSE; - auto cb_data = my_data->cbMap.find(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - skipCall = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true, image); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdClearDepthStencilImage"); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, - pRanges); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, - VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve *pRegions) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - VkBool32 skipCall = VK_FALSE; - auto cb_data = my_data->cbMap.find(commandBuffer); - loader_platform_thread_lock_mutex(&globalLock); - VkDeviceMemory mem; - skipCall = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = - [=]() { return validate_memory_is_valid(my_data, mem, "vkCmdResolveImage()", srcImage); }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdResolveImage"); - skipCall |= - get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, mem, true, dstImage); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdResolveImage"); - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, - regionCount, pRegions); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - my_data->device_dispatch_table->CmdBeginQuery(commandBuffer, queryPool, slot, flags); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - my_data->device_dispatch_table->CmdEndQuery(commandBuffer, queryPool, slot); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - my_data->device_dispatch_table->CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); - VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; - VkResult res = pTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback); - if (res == VK_SUCCESS) { - loader_platform_thread_lock_mutex(&globalLock); - res = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pMsgCallback); - loader_platform_thread_unlock_mutex(&globalLock); - } - return res; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, - VkDebugReportCallbackEXT msgCallback, - const VkAllocationCallbacks *pAllocator) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); - VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; - pTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator); - loader_platform_thread_lock_mutex(&globalLock); - layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator); - loader_platform_thread_unlock_mutex(&globalLock); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object, - size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); - my_data->instance_dispatch_table->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, - pMsg); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkSwapchainKHR *pSwapchain) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); - - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - add_swap_chain_info(my_data, *pSwapchain, pCreateInfo); - loader_platform_thread_unlock_mutex(&globalLock); - } - - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkBool32 skipCall = VK_FALSE; - loader_platform_thread_lock_mutex(&globalLock); - if (my_data->swapchainMap.find(swapchain) != my_data->swapchainMap.end()) { - MT_SWAP_CHAIN_INFO *pInfo = my_data->swapchainMap[swapchain]; - - if (pInfo->images.size() > 0) { - for (auto it = pInfo->images.begin(); it != pInfo->images.end(); it++) { - skipCall = clear_object_binding(my_data, device, (uint64_t)*it, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT); - auto image_item = my_data->imageMap.find((uint64_t)*it); - if (image_item != my_data->imageMap.end()) - my_data->imageMap.erase(image_item); - } - } - delete pInfo; - my_data->swapchainMap.erase(swapchain); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - my_data->device_dispatch_table->DestroySwapchainKHR(device, swapchain, pAllocator); - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount, VkImage *pSwapchainImages) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages); - - loader_platform_thread_lock_mutex(&globalLock); - if (result == VK_SUCCESS && pSwapchainImages != NULL) { - const size_t count = *pCount; - MT_SWAP_CHAIN_INFO *pInfo = my_data->swapchainMap[swapchain]; - - if (pInfo->images.empty()) { - pInfo->images.resize(count); - memcpy(&pInfo->images[0], pSwapchainImages, sizeof(pInfo->images[0]) * count); - - if (pInfo->images.size() > 0) { - for (std::vector<VkImage>::const_iterator it = pInfo->images.begin(); it != pInfo->images.end(); it++) { - // Add image object binding, then insert the new Mem Object and then bind it to created image - add_object_create_info(my_data, (uint64_t)*it, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, - &pInfo->createInfo); - } - } - } else { - const size_t count = *pCount; - MT_SWAP_CHAIN_INFO *pInfo = my_data->swapchainMap[swapchain]; - const VkBool32 mismatch = - (pInfo->images.size() != count || memcmp(&pInfo->images[0], pSwapchainImages, sizeof(pInfo->images[0]) * count)); - - if (mismatch) { - // TODO: Verify against Valid Usage section of extension - log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, - (uint64_t)swapchain, __LINE__, MEMTRACK_NONE, "SWAP_CHAIN", - "vkGetSwapchainInfoKHR(%" PRIu64 - ", VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR) returned mismatching data", - (uint64_t)(swapchain)); - } - } - } - loader_platform_thread_unlock_mutex(&globalLock); - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, - VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - VkBool32 skipCall = VK_FALSE; - - loader_platform_thread_lock_mutex(&globalLock); - if (my_data->semaphoreMap.find(semaphore) != my_data->semaphoreMap.end()) { - if (my_data->semaphoreMap[semaphore] != MEMTRACK_SEMAPHORE_STATE_UNSET) { - skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, - (uint64_t)semaphore, __LINE__, MEMTRACK_NONE, "SEMAPHORE", - "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state"); - } - my_data->semaphoreMap[semaphore] = MEMTRACK_SEMAPHORE_STATE_SIGNALLED; - } - auto fence_data = my_data->fenceMap.find(fence); - if (fence_data != my_data->fenceMap.end()) { - fence_data->second.swapchain = swapchain; - } - loader_platform_thread_unlock_mutex(&globalLock); - if (VK_FALSE == skipCall) { - result = my_data->device_dispatch_table->AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex); - } - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) { - VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map); - VkBool32 skip_call = false; - VkDeviceMemory mem; - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) { - MT_SWAP_CHAIN_INFO *pInfo = my_data->swapchainMap[pPresentInfo->pSwapchains[i]]; - VkImage image = pInfo->images[pPresentInfo->pImageIndices[i]]; - skip_call |= get_mem_binding_from_object(my_data, queue, (uint64_t)(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem); - skip_call |= validate_memory_is_valid(my_data, mem, "vkQueuePresentKHR()", image); - } - loader_platform_thread_unlock_mutex(&globalLock); - if (!skip_call) { - result = my_data->device_dispatch_table->QueuePresentKHR(queue, pPresentInfo); - } - - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; i++) { - VkSemaphore sem = pPresentInfo->pWaitSemaphores[i]; - if (my_data->semaphoreMap.find(sem) != my_data->semaphoreMap.end()) { - my_data->semaphoreMap[sem] = MEMTRACK_SEMAPHORE_STATE_UNSET; - } - } - loader_platform_thread_unlock_mutex(&globalLock); - - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore); - loader_platform_thread_lock_mutex(&globalLock); - if (*pSemaphore != VK_NULL_HANDLE) { - my_data->semaphoreMap[*pSemaphore] = MEMTRACK_SEMAPHORE_STATE_UNSET; - } - loader_platform_thread_unlock_mutex(&globalLock); - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - auto item = my_data->semaphoreMap.find(semaphore); - if (item != my_data->semaphoreMap.end()) { - my_data->semaphoreMap.erase(item); - } - loader_platform_thread_unlock_mutex(&globalLock); - my_data->device_dispatch_table->DestroySemaphore(device, semaphore, pAllocator); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkFramebuffer *pFramebuffer) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer); - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { - VkImageView view = pCreateInfo->pAttachments[i]; - auto view_data = my_data->imageViewMap.find(view); - if (view_data == my_data->imageViewMap.end()) { - continue; - } - MT_FB_ATTACHMENT_INFO fb_info; - get_mem_binding_from_object(my_data, device, (uint64_t)(view_data->second.image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - &fb_info.mem); - fb_info.image = view_data->second.image; - my_data->fbMap[*pFramebuffer].attachments.push_back(fb_info); - } - loader_platform_thread_unlock_mutex(&globalLock); - return result; -} - -VKAPI_ATTR void VKAPI_CALL -vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - - loader_platform_thread_lock_mutex(&globalLock); - auto item = my_data->fbMap.find(framebuffer); - if (item != my_data->fbMap.end()) { - my_data->fbMap.erase(framebuffer); - } - loader_platform_thread_unlock_mutex(&globalLock); - - my_data->device_dispatch_table->DestroyFramebuffer(device, framebuffer, pAllocator); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkRenderPass *pRenderPass) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass); - loader_platform_thread_lock_mutex(&globalLock); - for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { - VkAttachmentDescription desc = pCreateInfo->pAttachments[i]; - MT_PASS_ATTACHMENT_INFO pass_info; - pass_info.load_op = desc.loadOp; - pass_info.store_op = desc.storeOp; - pass_info.attachment = i; - my_data->passMap[*pRenderPass].attachments.push_back(pass_info); - } - // TODO: Maybe fill list and then copy instead of locking - std::unordered_map<uint32_t, bool> &attachment_first_read = my_data->passMap[*pRenderPass].attachment_first_read; - std::unordered_map<uint32_t, VkImageLayout> &attachment_first_layout = my_data->passMap[*pRenderPass].attachment_first_layout; - for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; - for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { - uint32_t attachment = subpass.pInputAttachments[j].attachment; - if (attachment_first_read.count(attachment)) - continue; - attachment_first_read.insert(std::make_pair(attachment, true)); - attachment_first_layout.insert(std::make_pair(attachment, subpass.pInputAttachments[j].layout)); - } - for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { - uint32_t attachment = subpass.pColorAttachments[j].attachment; - if (attachment_first_read.count(attachment)) - continue; - attachment_first_read.insert(std::make_pair(attachment, false)); - attachment_first_layout.insert(std::make_pair(attachment, subpass.pColorAttachments[j].layout)); - } - if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { - uint32_t attachment = subpass.pDepthStencilAttachment->attachment; - if (attachment_first_read.count(attachment)) - continue; - attachment_first_read.insert(std::make_pair(attachment, false)); - attachment_first_layout.insert(std::make_pair(attachment, subpass.pDepthStencilAttachment->layout)); - } - } - loader_platform_thread_unlock_mutex(&globalLock); - - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - my_data->device_dispatch_table->DestroyRenderPass(device, renderPass, pAllocator); - - loader_platform_thread_lock_mutex(&globalLock); - my_data->passMap.erase(renderPass); - loader_platform_thread_unlock_mutex(&globalLock); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdBeginRenderPass(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, VkSubpassContents contents) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); - VkBool32 skip_call = false; - if (pRenderPassBegin) { - loader_platform_thread_lock_mutex(&globalLock); - auto pass_data = my_data->passMap.find(pRenderPassBegin->renderPass); - if (pass_data != my_data->passMap.end()) { - MT_PASS_INFO &pass_info = pass_data->second; - pass_info.fb = pRenderPassBegin->framebuffer; - auto cb_data = my_data->cbMap.find(cmdBuffer); - for (size_t i = 0; i < pass_info.attachments.size(); ++i) { - MT_FB_ATTACHMENT_INFO &fb_info = my_data->fbMap[pass_info.fb].attachments[i]; - if (pass_info.attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) { - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, fb_info.mem, true, fb_info.image); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - VkImageLayout &attachment_layout = pass_info.attachment_first_layout[pass_info.attachments[i].attachment]; - if (attachment_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL || - attachment_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - skip_call |= - log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, (uint64_t)(pRenderPassBegin->renderPass), __LINE__, - MEMTRACK_INVALID_LAYOUT, "MEM", "Cannot clear attachment %d with invalid first layout %d.", - pass_info.attachments[i].attachment, attachment_layout); - } - } else if (pass_info.attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_DONT_CARE) { - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, fb_info.mem, false, fb_info.image); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - } else if (pass_info.attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_LOAD) { - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - return validate_memory_is_valid(my_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image); - }; - cb_data->second.validate_functions.push_back(function); - } - } - if (pass_info.attachment_first_read[pass_info.attachments[i].attachment]) { - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - return validate_memory_is_valid(my_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image); - }; - cb_data->second.validate_functions.push_back(function); - } - } - } - if (cb_data != my_data->cbMap.end()) { - cb_data->second.pass = pRenderPassBegin->renderPass; - } - } - loader_platform_thread_unlock_mutex(&globalLock); - } - if (!skip_call) - return my_data->device_dispatch_table->CmdBeginRenderPass(cmdBuffer, pRenderPassBegin, contents); -} - -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass(VkCommandBuffer cmdBuffer) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map); - loader_platform_thread_lock_mutex(&globalLock); - auto cb_data = my_data->cbMap.find(cmdBuffer); - if (cb_data != my_data->cbMap.end()) { - auto pass_data = my_data->passMap.find(cb_data->second.pass); - if (pass_data != my_data->passMap.end()) { - MT_PASS_INFO &pass_info = pass_data->second; - for (size_t i = 0; i < pass_info.attachments.size(); ++i) { - MT_FB_ATTACHMENT_INFO &fb_info = my_data->fbMap[pass_info.fb].attachments[i]; - if (pass_info.attachments[i].store_op == VK_ATTACHMENT_STORE_OP_STORE) { - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, fb_info.mem, true, fb_info.image); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - } else if (pass_info.attachments[i].store_op == VK_ATTACHMENT_STORE_OP_DONT_CARE) { - if (cb_data != my_data->cbMap.end()) { - std::function<VkBool32()> function = [=]() { - set_memory_valid(my_data, fb_info.mem, false, fb_info.image); - return VK_FALSE; - }; - cb_data->second.validate_functions.push_back(function); - } - } - } - } - } - loader_platform_thread_unlock_mutex(&globalLock); - my_data->device_dispatch_table->CmdEndRenderPass(cmdBuffer); -} - -VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) { - if (!strcmp(funcName, "vkGetDeviceProcAddr")) - return (PFN_vkVoidFunction)vkGetDeviceProcAddr; - if (!strcmp(funcName, "vkDestroyDevice")) - return (PFN_vkVoidFunction)vkDestroyDevice; - if (!strcmp(funcName, "vkQueueSubmit")) - return (PFN_vkVoidFunction)vkQueueSubmit; - if (!strcmp(funcName, "vkAllocateMemory")) - return (PFN_vkVoidFunction)vkAllocateMemory; - if (!strcmp(funcName, "vkFreeMemory")) - return (PFN_vkVoidFunction)vkFreeMemory; - if (!strcmp(funcName, "vkMapMemory")) - return (PFN_vkVoidFunction)vkMapMemory; - if (!strcmp(funcName, "vkUnmapMemory")) - return (PFN_vkVoidFunction)vkUnmapMemory; - if (!strcmp(funcName, "vkFlushMappedMemoryRanges")) - return (PFN_vkVoidFunction)vkFlushMappedMemoryRanges; - if (!strcmp(funcName, "vkInvalidateMappedMemoryRanges")) - return (PFN_vkVoidFunction)vkInvalidateMappedMemoryRanges; - if (!strcmp(funcName, "vkDestroyFence")) - return (PFN_vkVoidFunction)vkDestroyFence; - if (!strcmp(funcName, "vkDestroyBuffer")) - return (PFN_vkVoidFunction)vkDestroyBuffer; - if (!strcmp(funcName, "vkDestroyBufferView")) - return (PFN_vkVoidFunction)vkDestroyBufferView; - if (!strcmp(funcName, "vkDestroyImage")) - return (PFN_vkVoidFunction)vkDestroyImage; - if (!strcmp(funcName, "vkBindBufferMemory")) - return (PFN_vkVoidFunction)vkBindBufferMemory; - if (!strcmp(funcName, "vkBindImageMemory")) - return (PFN_vkVoidFunction)vkBindImageMemory; - if (!strcmp(funcName, "vkGetBufferMemoryRequirements")) - return (PFN_vkVoidFunction)vkGetBufferMemoryRequirements; - if (!strcmp(funcName, "vkGetImageMemoryRequirements")) - return (PFN_vkVoidFunction)vkGetImageMemoryRequirements; - if (!strcmp(funcName, "vkQueueBindSparse")) - return (PFN_vkVoidFunction)vkQueueBindSparse; - if (!strcmp(funcName, "vkCreateFence")) - return (PFN_vkVoidFunction)vkCreateFence; - if (!strcmp(funcName, "vkGetFenceStatus")) - return (PFN_vkVoidFunction)vkGetFenceStatus; - if (!strcmp(funcName, "vkResetFences")) - return (PFN_vkVoidFunction)vkResetFences; - if (!strcmp(funcName, "vkWaitForFences")) - return (PFN_vkVoidFunction)vkWaitForFences; - if (!strcmp(funcName, "vkCreateSemaphore")) - return (PFN_vkVoidFunction)vkCreateSemaphore; - if (!strcmp(funcName, "vkDestroySemaphore")) - return (PFN_vkVoidFunction)vkDestroySemaphore; - if (!strcmp(funcName, "vkQueueWaitIdle")) - return (PFN_vkVoidFunction)vkQueueWaitIdle; - if (!strcmp(funcName, "vkDeviceWaitIdle")) - return (PFN_vkVoidFunction)vkDeviceWaitIdle; - if (!strcmp(funcName, "vkCreateBuffer")) - return (PFN_vkVoidFunction)vkCreateBuffer; - if (!strcmp(funcName, "vkCreateImage")) - return (PFN_vkVoidFunction)vkCreateImage; - if (!strcmp(funcName, "vkCreateImageView")) - return (PFN_vkVoidFunction)vkCreateImageView; - if (!strcmp(funcName, "vkCreateBufferView")) - return (PFN_vkVoidFunction)vkCreateBufferView; - if (!strcmp(funcName, "vkUpdateDescriptorSets")) - return (PFN_vkVoidFunction)vkUpdateDescriptorSets; - if (!strcmp(funcName, "vkAllocateCommandBuffers")) - return (PFN_vkVoidFunction)vkAllocateCommandBuffers; - if (!strcmp(funcName, "vkFreeCommandBuffers")) - return (PFN_vkVoidFunction)vkFreeCommandBuffers; - if (!strcmp(funcName, "vkCreateCommandPool")) - return (PFN_vkVoidFunction)vkCreateCommandPool; - if (!strcmp(funcName, "vkDestroyCommandPool")) - return (PFN_vkVoidFunction)vkDestroyCommandPool; - if (!strcmp(funcName, "vkResetCommandPool")) - return (PFN_vkVoidFunction)vkResetCommandPool; - if (!strcmp(funcName, "vkBeginCommandBuffer")) - return (PFN_vkVoidFunction)vkBeginCommandBuffer; - if (!strcmp(funcName, "vkEndCommandBuffer")) - return (PFN_vkVoidFunction)vkEndCommandBuffer; - if (!strcmp(funcName, "vkResetCommandBuffer")) - return (PFN_vkVoidFunction)vkResetCommandBuffer; - if (!strcmp(funcName, "vkCmdBindPipeline")) - return (PFN_vkVoidFunction)vkCmdBindPipeline; - if (!strcmp(funcName, "vkCmdBindDescriptorSets")) - return (PFN_vkVoidFunction)vkCmdBindDescriptorSets; - if (!strcmp(funcName, "vkCmdBindVertexBuffers")) - return (PFN_vkVoidFunction)vkCmdBindVertexBuffers; - if (!strcmp(funcName, "vkCmdBindIndexBuffer")) - return (PFN_vkVoidFunction)vkCmdBindIndexBuffer; - if (!strcmp(funcName, "vkCmdBlitImage")) - return (PFN_vkVoidFunction)vkCmdBlitImage; - if (!strcmp(funcName, "vkCmdDraw")) - return (PFN_vkVoidFunction)vkCmdDraw; - if (!strcmp(funcName, "vkCmdDrawIndexed")) - return (PFN_vkVoidFunction)vkCmdDrawIndexed; - if (!strcmp(funcName, "vkCmdDrawIndirect")) - return (PFN_vkVoidFunction)vkCmdDrawIndirect; - if (!strcmp(funcName, "vkCmdDrawIndexedIndirect")) - return (PFN_vkVoidFunction)vkCmdDrawIndexedIndirect; - if (!strcmp(funcName, "vkCmdDispatch")) - return (PFN_vkVoidFunction)vkCmdDispatch; - if (!strcmp(funcName, "vkCmdDispatchIndirect")) - return (PFN_vkVoidFunction)vkCmdDispatchIndirect; - if (!strcmp(funcName, "vkCmdCopyBuffer")) - return (PFN_vkVoidFunction)vkCmdCopyBuffer; - if (!strcmp(funcName, "vkCmdCopyQueryPoolResults")) - return (PFN_vkVoidFunction)vkCmdCopyQueryPoolResults; - if (!strcmp(funcName, "vkCmdCopyImage")) - return (PFN_vkVoidFunction)vkCmdCopyImage; - if (!strcmp(funcName, "vkCmdCopyBufferToImage")) - return (PFN_vkVoidFunction)vkCmdCopyBufferToImage; - if (!strcmp(funcName, "vkCmdCopyImageToBuffer")) - return (PFN_vkVoidFunction)vkCmdCopyImageToBuffer; - if (!strcmp(funcName, "vkCmdUpdateBuffer")) - return (PFN_vkVoidFunction)vkCmdUpdateBuffer; - if (!strcmp(funcName, "vkCmdFillBuffer")) - return (PFN_vkVoidFunction)vkCmdFillBuffer; - if (!strcmp(funcName, "vkCmdClearColorImage")) - return (PFN_vkVoidFunction)vkCmdClearColorImage; - if (!strcmp(funcName, "vkCmdClearDepthStencilImage")) - return (PFN_vkVoidFunction)vkCmdClearDepthStencilImage; - if (!strcmp(funcName, "vkCmdResolveImage")) - return (PFN_vkVoidFunction)vkCmdResolveImage; - if (!strcmp(funcName, "vkCmdBeginQuery")) - return (PFN_vkVoidFunction)vkCmdBeginQuery; - if (!strcmp(funcName, "vkCmdEndQuery")) - return (PFN_vkVoidFunction)vkCmdEndQuery; - if (!strcmp(funcName, "vkCmdResetQueryPool")) - return (PFN_vkVoidFunction)vkCmdResetQueryPool; - if (!strcmp(funcName, "vkCreateRenderPass")) - return (PFN_vkVoidFunction)vkCreateRenderPass; - if (!strcmp(funcName, "vkDestroyRenderPass")) - return (PFN_vkVoidFunction)vkDestroyRenderPass; - if (!strcmp(funcName, "vkCmdBeginRenderPass")) - return (PFN_vkVoidFunction)vkCmdBeginRenderPass; - if (!strcmp(funcName, "vkCmdEndRenderPass")) - return (PFN_vkVoidFunction)vkCmdEndRenderPass; - if (!strcmp(funcName, "vkGetDeviceQueue")) - return (PFN_vkVoidFunction)vkGetDeviceQueue; - if (!strcmp(funcName, "vkCreateFramebuffer")) - return (PFN_vkVoidFunction)vkCreateFramebuffer; - if (!strcmp(funcName, "vkDestroyFramebuffer")) - return (PFN_vkVoidFunction)vkDestroyFramebuffer; - - if (dev == NULL) - return NULL; - - layer_data *my_data; - my_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map); - if (my_data->wsi_enabled) { - if (!strcmp(funcName, "vkCreateSwapchainKHR")) - return (PFN_vkVoidFunction)vkCreateSwapchainKHR; - if (!strcmp(funcName, "vkDestroySwapchainKHR")) - return (PFN_vkVoidFunction)vkDestroySwapchainKHR; - if (!strcmp(funcName, "vkGetSwapchainImagesKHR")) - return (PFN_vkVoidFunction)vkGetSwapchainImagesKHR; - if (!strcmp(funcName, "vkAcquireNextImageKHR")) - return (PFN_vkVoidFunction)vkAcquireNextImageKHR; - if (!strcmp(funcName, "vkQueuePresentKHR")) - return (PFN_vkVoidFunction)vkQueuePresentKHR; - } - - VkLayerDispatchTable *pDisp = my_data->device_dispatch_table; - if (pDisp->GetDeviceProcAddr == NULL) - return NULL; - return pDisp->GetDeviceProcAddr(dev, funcName); -} - -VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) { - PFN_vkVoidFunction fptr; - - if (!strcmp(funcName, "vkGetInstanceProcAddr")) - return (PFN_vkVoidFunction)vkGetInstanceProcAddr; - if (!strcmp(funcName, "vkGetDeviceProcAddr")) - return (PFN_vkVoidFunction)vkGetDeviceProcAddr; - if (!strcmp(funcName, "vkDestroyInstance")) - return (PFN_vkVoidFunction)vkDestroyInstance; - if (!strcmp(funcName, "vkCreateInstance")) - return (PFN_vkVoidFunction)vkCreateInstance; - if (!strcmp(funcName, "vkGetPhysicalDeviceMemoryProperties")) - return (PFN_vkVoidFunction)vkGetPhysicalDeviceMemoryProperties; - if (!strcmp(funcName, "vkCreateDevice")) - return (PFN_vkVoidFunction)vkCreateDevice; - if (!strcmp(funcName, "vkEnumerateInstanceLayerProperties")) - return (PFN_vkVoidFunction)vkEnumerateInstanceLayerProperties; - if (!strcmp(funcName, "vkEnumerateInstanceExtensionProperties")) - return (PFN_vkVoidFunction)vkEnumerateInstanceExtensionProperties; - if (!strcmp(funcName, "vkEnumerateDeviceLayerProperties")) - return (PFN_vkVoidFunction)vkEnumerateDeviceLayerProperties; - if (!strcmp(funcName, "vkEnumerateDeviceExtensionProperties")) - return (PFN_vkVoidFunction)vkEnumerateDeviceExtensionProperties; - - if (instance == NULL) - return NULL; - - layer_data *my_data; - my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); - - fptr = debug_report_get_instance_proc_addr(my_data->report_data, funcName); - if (fptr) - return fptr; - - VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; - if (pTable->GetInstanceProcAddr == NULL) - return NULL; - return pTable->GetInstanceProcAddr(instance, funcName); -} diff --git a/layers/mem_tracker.h b/layers/mem_tracker.h deleted file mode 100644 index 9c024666..00000000 --- a/layers/mem_tracker.h +++ /dev/null @@ -1,218 +0,0 @@ -/* Copyright (c) 2015-2016 The Khronos Group Inc. - * Copyright (c) 2015-2016 Valve Corporation - * Copyright (c) 2015-2016 LunarG, Inc. - * Copyright (C) 2015-2016 Google Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and/or associated documentation files (the "Materials"), to - * deal in the Materials without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Materials, and to permit persons to whom the Materials - * are furnished to do so, subject to the following conditions: - * - * The above copyright notice(s) and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE - * USE OR OTHER DEALINGS IN THE MATERIALS - * - * Author: Tobin Ehlis <tobin@lunarg.com> - * Author: Mark Lobodzinski <mark@lunarg.com> - */ - -#pragma once -#include <vector> -#include <unordered_map> -#include "vulkan/vk_layer.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Mem Tracker ERROR codes -typedef enum _MEM_TRACK_ERROR { - MEMTRACK_NONE, // Used for INFO & other non-error messages - MEMTRACK_INVALID_CB, // Cmd Buffer invalid - MEMTRACK_INVALID_MEM_OBJ, // Invalid Memory Object - MEMTRACK_INVALID_ALIASING, // Invalid Memory Aliasing - MEMTRACK_INVALID_LAYOUT, // Invalid Layout - MEMTRACK_INTERNAL_ERROR, // Bug in Mem Track Layer internal data structures - MEMTRACK_FREED_MEM_REF, // MEM Obj freed while it still has obj and/or CB refs - MEMTRACK_MEM_OBJ_CLEAR_EMPTY_BINDINGS, // Clearing bindings on mem obj that doesn't have any bindings - MEMTRACK_MISSING_MEM_BINDINGS, // Trying to retrieve mem bindings, but none found (may be internal error) - MEMTRACK_INVALID_OBJECT, // Attempting to reference generic VK Object that is invalid - MEMTRACK_MEMORY_BINDING_ERROR, // Error during one of many calls that bind memory to object or CB - MEMTRACK_MEMORY_LEAK, // Failure to call vkFreeMemory on Mem Obj prior to DestroyDevice - MEMTRACK_INVALID_STATE, // Memory not in the correct state - MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, // vkResetCommandBuffer() called on a CB that hasn't completed - MEMTRACK_INVALID_FENCE_STATE, // Invalid Fence State signaled or used - MEMTRACK_REBIND_OBJECT, // Non-sparse object bindings are immutable - MEMTRACK_INVALID_USAGE_FLAG, // Usage flags specified at image/buffer create conflict w/ use of object - MEMTRACK_INVALID_MAP, // Size flag specified at alloc is too small for mapping range -} MEM_TRACK_ERROR; - -// MemTracker Semaphore states -typedef enum _MtSemaphoreState { - MEMTRACK_SEMAPHORE_STATE_UNSET, // Semaphore is in an undefined state - MEMTRACK_SEMAPHORE_STATE_SIGNALLED, // Semaphore has is in signalled state - MEMTRACK_SEMAPHORE_STATE_WAIT, // Semaphore is in wait state -} MtSemaphoreState; - -struct MemRange { - VkDeviceSize offset; - VkDeviceSize size; -}; - -/* - * Data Structure overview - * There are 4 global STL(' maps - * cbMap -- map of command Buffer (CB) objects to MT_CB_INFO structures - * Each MT_CB_INFO struct has an stl list container with - * memory objects that are referenced by this CB - * memObjMap -- map of Memory Objects to MT_MEM_OBJ_INFO structures - * Each MT_MEM_OBJ_INFO has two stl list containers with: - * -- all CBs referencing this mem obj - * -- all VK Objects that are bound to this memory - * objectMap -- map of objects to MT_OBJ_INFO structures - * - * Algorithm overview - * These are the primary events that should happen related to different objects - * 1. Command buffers - * CREATION - Add object,structure to map - * CMD BIND - If mem associated, add mem reference to list container - * DESTROY - Remove from map, decrement (and report) mem references - * 2. Mem Objects - * CREATION - Add object,structure to map - * OBJ BIND - Add obj structure to list container for that mem node - * CMB BIND - If mem-related add CB structure to list container for that mem node - * DESTROY - Flag as errors any remaining refs and remove from map - * 3. Generic Objects - * MEM BIND - DESTROY any previous binding, Add obj node w/ ref to map, add obj ref to list container for that mem node - * DESTROY - If mem bound, remove reference list container for that memInfo, remove object ref from map - */ -// TODO : Is there a way to track when Cmd Buffer finishes & remove mem references at that point? -// TODO : Could potentially store a list of freed mem allocs to flag when they're incorrectly used - -// Simple struct to hold handle and type of object so they can be uniquely identified and looked up in appropriate map -struct MT_OBJ_HANDLE_TYPE { - uint64_t handle; - VkDebugReportObjectTypeEXT type; -}; - -// Data struct for tracking memory object -struct MT_MEM_OBJ_INFO { - void *object; // Dispatchable object used to create this memory (device of swapchain) - uint32_t refCount; // Count of references (obj bindings or CB use) - bool valid; // Stores if the memory has valid data or not - VkDeviceMemory mem; - VkMemoryAllocateInfo allocInfo; - list<MT_OBJ_HANDLE_TYPE> pObjBindings; // list container of objects bound to this memory - list<VkCommandBuffer> pCommandBufferBindings; // list container of cmd buffers that reference this mem object - MemRange memRange; - void *pData, *pDriverData; -}; - -// This only applies to Buffers and Images, which can have memory bound to them -struct MT_OBJ_BINDING_INFO { - VkDeviceMemory mem; - bool valid; // If this is a swapchain image backing memory is not a MT_MEM_OBJ_INFO so store it here. - union create_info { - VkImageCreateInfo image; - VkBufferCreateInfo buffer; - } create_info; -}; - -// Track all command buffers -typedef struct _MT_CB_INFO { - VkCommandBufferAllocateInfo createInfo; - VkPipeline pipelines[VK_PIPELINE_BIND_POINT_RANGE_SIZE]; - uint32_t attachmentCount; - VkCommandBuffer commandBuffer; - uint64_t fenceId; - VkFence lastSubmittedFence; - VkQueue lastSubmittedQueue; - VkRenderPass pass; - vector<VkDescriptorSet> activeDescriptorSets; - vector<std::function<VkBool32()>> validate_functions; - // Order dependent, stl containers must be at end of struct - list<VkDeviceMemory> pMemObjList; // List container of Mem objs referenced by this CB - // Constructor - _MT_CB_INFO() : createInfo{}, pipelines{}, attachmentCount(0), fenceId(0), lastSubmittedFence{}, lastSubmittedQueue{} {}; -} MT_CB_INFO; - -// Track command pools and their command buffers -typedef struct _MT_CMD_POOL_INFO { - VkCommandPoolCreateFlags createFlags; - list<VkCommandBuffer> pCommandBuffers; // list container of cmd buffers allocated from this pool -} MT_CMD_POOL_INFO; - -struct MT_IMAGE_VIEW_INFO { - VkImage image; -}; - -struct MT_FB_ATTACHMENT_INFO { - VkImage image; - VkDeviceMemory mem; -}; - -struct MT_FB_INFO { - std::vector<MT_FB_ATTACHMENT_INFO> attachments; -}; - -struct MT_PASS_ATTACHMENT_INFO { - uint32_t attachment; - VkAttachmentLoadOp load_op; - VkAttachmentStoreOp store_op; -}; - -struct MT_PASS_INFO { - VkFramebuffer fb; - std::vector<MT_PASS_ATTACHMENT_INFO> attachments; - std::unordered_map<uint32_t, bool> attachment_first_read; - std::unordered_map<uint32_t, VkImageLayout> attachment_first_layout; -}; - -// Associate fenceId with a fence object -struct MT_FENCE_INFO { - uint64_t fenceId; // Sequence number for fence at last submit - VkQueue queue; // Queue that this fence is submitted against or NULL - VkSwapchainKHR swapchain; // Swapchain that this fence is submitted against or NULL - VkBool32 firstTimeFlag; // Fence was created in signaled state, avoid warnings for first use - VkFenceCreateInfo createInfo; -}; - -// Track Queue information -struct MT_QUEUE_INFO { - uint64_t lastRetiredId; - uint64_t lastSubmittedId; - list<VkCommandBuffer> pQueueCommandBuffers; - list<VkDeviceMemory> pMemRefList; -}; - -struct MT_DESCRIPTOR_SET_INFO { - std::vector<VkImageView> images; - std::vector<VkBuffer> buffers; -}; - -// Track Swapchain Information -struct MT_SWAP_CHAIN_INFO { - VkSwapchainCreateInfoKHR createInfo; - std::vector<VkImage> images; -}; - -struct MEMORY_RANGE { - uint64_t handle; - VkDeviceMemory memory; - VkDeviceSize start; - VkDeviceSize end; -}; - -#ifdef __cplusplus -} -#endif diff --git a/layers/vk_layer_settings.txt b/layers/vk_layer_settings.txt index 36fecb28..cdbb1dae 100644 --- a/layers/vk_layer_settings.txt +++ b/layers/vk_layer_settings.txt @@ -60,21 +60,11 @@ lunarg_core_validation.debug_action = VK_DBG_LAYER_ACTION_LOG_MSG lunarg_core_validation.report_flags = error,warn,perf lunarg_core_validation.log_filename = stdout -# VK_LAYER_LUNARG_draw_state Settings -lunarg_draw_state.debug_action = VK_DBG_LAYER_ACTION_LOG_MSG -lunarg_draw_state.report_flags = error,warn,perf -lunarg_draw_state.log_filename = stdout - # VK_LAYER_LUNARG_image Settings lunarg_image.debug_action = VK_DBG_LAYER_ACTION_LOG_MSG lunarg_image.report_flags = error,warn,perf lunarg_image.log_filename = stdout -# VK_LAYER_LUNARG_mem_tracker Settings -lunarg_mem_tracker.debug_action = VK_DBG_LAYER_ACTION_LOG_MSG -lunarg_mem_tracker.report_flags = error,warn,perf -lunarg_mem_tracker.log_filename = stdout - # VK_LAYER_LUNARG_object_tracker Settings lunarg_object_tracker.debug_action = VK_DBG_LAYER_ACTION_LOG_MSG lunarg_object_tracker.report_flags = error,warn,perf diff --git a/layers/windows/VkLayer_draw_state.json b/layers/windows/VkLayer_draw_state.json deleted file mode 100644 index e95f78a5..00000000 --- a/layers/windows/VkLayer_draw_state.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "file_format_version" : "1.0.0", - "layer" : { - "name": "VK_LAYER_LUNARG_draw_state", - "type": "GLOBAL", - "library_path": ".\\VkLayer_draw_state.dll", - "api_version": "1.0.5", - "implementation_version": "1", - "description": "LunarG Validation Layer", - "instance_extensions": [ - { - "name": "VK_EXT_debug_report", - "spec_version": "2" - } - ] - } -} diff --git a/layers/windows/VkLayer_mem_tracker.json b/layers/windows/VkLayer_mem_tracker.json deleted file mode 100644 index c3586b1c..00000000 --- a/layers/windows/VkLayer_mem_tracker.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "file_format_version" : "1.0.0", - "layer" : { - "name": "VK_LAYER_LUNARG_mem_tracker", - "type": "GLOBAL", - "library_path": ".\\VkLayer_mem_tracker.dll", - "api_version": "1.0.5", - "implementation_version": "1", - "description": "LunarG Validation Layer", - "instance_extensions": [ - { - "name": "VK_EXT_debug_report", - "spec_version": "2" - } - ] - } -} diff --git a/loader/loader.h b/loader/loader.h index 75b99bb6..ae51725c 100644 --- a/loader/loader.h +++ b/loader/loader.h @@ -82,12 +82,11 @@ static const char UTF8_THREE_BYTE_MASK = 0xF8; static const char UTF8_DATA_BYTE_CODE = 0x80; static const char UTF8_DATA_BYTE_MASK = 0xC0; -static const char std_validation_names[9][VK_MAX_EXTENSION_NAME_SIZE] = { +static const char std_validation_names[8][VK_MAX_EXTENSION_NAME_SIZE] = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_param_checker", "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker", - "VK_LAYER_LUNARG_image", "VK_LAYER_LUNARG_mem_tracker", - "VK_LAYER_LUNARG_draw_state", "VK_LAYER_LUNARG_swapchain", - "VK_LAYER_GOOGLE_unique_objects"}; + "VK_LAYER_LUNARG_image", "VK_LAYER_LUNARG_core_validation", + "VK_LAYER_LUNARG_swapchain", "VK_LAYER_GOOGLE_unique_objects"}; // form of all dynamic lists/arrays // only the list element should be changed |
