diff options
| author | Tobin Ehlis <tobine@google.com> | 2015-12-01 09:48:58 -0700 |
|---|---|---|
| committer | Mark Lobodzinski <mark@lunarg.com> | 2015-12-07 14:36:49 -0700 |
| commit | faf9dac98d1d8f0e83b045cce23937619da8ae0a (patch) | |
| tree | 14fe4aa25e1e797f284dfc00e02efb6353abec6e /layers/shader_checker.cpp | |
| parent | b00af418b6f7c7a811e8c73bdc5b2cccb84bcba3 (diff) | |
| download | usermoji-faf9dac98d1d8f0e83b045cce23937619da8ae0a.tar.xz | |
layers: MR75, Merge DrawState and ShaderChecker into DrawState layer
This is the initial "dumb" merge where a few data structures are now duplicated
within DrawState. This is intentional to simplify the transition and a follow-on
commit will fix these inefficiencies.
Conflicts:
layers/draw_state.cpp
Diffstat (limited to 'layers/shader_checker.cpp')
| -rw-r--r-- | layers/shader_checker.cpp | 1340 |
1 files changed, 0 insertions, 1340 deletions
diff --git a/layers/shader_checker.cpp b/layers/shader_checker.cpp deleted file mode 100644 index fe4d4740..00000000 --- a/layers/shader_checker.cpp +++ /dev/null @@ -1,1340 +0,0 @@ -/* - * - * Copyright (C) 2015 Valve Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Author: Chia-I Wu <olv@lunarg.com> - * Author: Chris Forbes <chrisf@ijw.co.nz> - */ -#include <string.h> -#include <stdlib.h> -#include <assert.h> -#include <map> -#include <unordered_map> -#include <unordered_set> -#include <map> -#include <vector> -#include <string> -#include <iostream> -#include "vk_loader_platform.h" -#include "vk_dispatch_table_helper.h" -#include "vulkan/vk_layer.h" -#include "vk_layer_utils.h" -#include "vk_layer_config.h" -#include "vk_layer_table.h" -#include "vk_enum_string_helper.h" -#include "shader_checker.h" -#include "vk_layer_extension_utils.h" - -#include <spirv.hpp> - -// fwd decls -struct shader_module; -struct render_pass; - -struct layer_data { - debug_report_data *report_data; - std::vector<VkDbgMsgCallback> logging_callback; - VkLayerDispatchTable* device_dispatch_table; - VkLayerInstanceDispatchTable* instance_dispatch_table; - - std::unordered_map<VkShaderModule, shader_module *> shader_module_map; - std::unordered_map<VkDescriptorSetLayout, std::unordered_set<uint32_t>*> descriptor_set_layout_map; - std::unordered_map<VkPipelineLayout, std::vector<std::unordered_set<uint32_t>*>*> pipeline_layout_map; - std::unordered_map<VkRenderPass, render_pass *> render_pass_map; - - layer_data() : - report_data(nullptr), - device_dispatch_table(nullptr), - instance_dispatch_table(nullptr) - {}; -}; - -static void -build_type_def_index(std::vector<unsigned> const &words, std::unordered_map<unsigned, unsigned> &type_def_index); - -struct shader_module { - /* the spirv image itself */ - std::vector<uint32_t> words; - /* a mapping of <id> to the first word of its def. this is useful because walking type - * trees requires jumping all over the instruction stream. - */ - std::unordered_map<unsigned, unsigned> type_def_index; - - shader_module(VkShaderModuleCreateInfo const *pCreateInfo) : - words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)), - type_def_index() { - - build_type_def_index(words, type_def_index); - } -}; - -struct render_pass { - std::vector<std::vector<VkFormat>> subpass_color_formats; - - render_pass(VkRenderPassCreateInfo const *pCreateInfo) - { - uint32_t i; - - subpass_color_formats.reserve(pCreateInfo->subpassCount); - for (i = 0; i < pCreateInfo->subpassCount; i++) { - const VkSubpassDescription *subpass = &pCreateInfo->pSubpasses[i]; - std::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(pCreateInfo->pAttachments[att].format); - } - - subpass_color_formats.push_back(color_formats); - } - } -}; - -static std::unordered_map<void *, layer_data *> layer_data_map; - -template layer_data *get_my_data_ptr<layer_data>( - void *data_key, - std::unordered_map<void *, layer_data *> &data_map); - -static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(g_initOnce); -// TODO : This can be much smarter, using separate locks for separate global data -static int globalLockInitialized = 0; -static loader_platform_thread_mutex globalLock; - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout( - VkDevice device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorSetLayout* pSetLayout) -{ - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - /* stash a copy of the layout bindings */ - VkResult result = my_data->device_dispatch_table->CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout); - - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - auto& bindings = my_data->descriptor_set_layout_map[*pSetLayout]; - bindings = new std::unordered_set<uint32_t>(); - bindings->reserve(pCreateInfo->bindingCount); - for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) - bindings->insert(pCreateInfo->pBinding[i].binding); - - loader_platform_thread_unlock_mutex(&globalLock); - } - - return result; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout( - VkDevice device, - const VkPipelineLayoutCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkPipelineLayout* pPipelineLayout) -{ - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult result = my_data->device_dispatch_table->CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout); - - if (VK_SUCCESS == result) { - loader_platform_thread_lock_mutex(&globalLock); - auto& layouts = my_data->pipeline_layout_map[*pPipelineLayout]; - layouts = new std::vector<std::unordered_set<uint32_t>*>(); - layouts->reserve(pCreateInfo->setLayoutCount); - for (unsigned i = 0; i < pCreateInfo->setLayoutCount; i++) { - layouts->push_back(my_data->descriptor_set_layout_map[pCreateInfo->pSetLayouts[i]]); - } - loader_platform_thread_unlock_mutex(&globalLock); - } - - return result; -} - -static void -build_type_def_index(std::vector<unsigned> const &words, std::unordered_map<unsigned, unsigned> &type_def_index) -{ - unsigned int const *code = (unsigned int const *)&words[0]; - size_t size = words.size(); - - unsigned word = 5; - while (word < size) { - unsigned opcode = code[word] & 0x0ffffu; - unsigned oplen = (code[word] & 0xffff0000u) >> 16; - - switch (opcode) { - 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: - type_def_index[code[word+1]] = word; - break; - - default: - /* We only care about type definitions */ - break; - } - - word += oplen; - } -} - -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 void -init_shader_checker(layer_data *my_data) -{ - uint32_t report_flags = 0; - uint32_t debug_action = 0; - FILE *log_output = NULL; - const char *option_str; - VkDbgMsgCallback callback; - // initialize ShaderChecker options - report_flags = getLayerOptionFlags("ShaderCheckerReportFlags", 0); - getLayerOptionEnum("ShaderCheckerDebugAction", (uint32_t *) &debug_action); - - if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG) - { - option_str = getLayerOption("ShaderCheckerLogFilename"); - log_output = getLayerLogOutput(option_str, "ShaderChecker"); - layer_create_msg_callback(my_data->report_data, report_flags, log_callback, (void *) log_output, &callback); - my_data->logging_callback.push_back(callback); - } - - if (debug_action & VK_DBG_LAYER_ACTION_DEBUG_OUTPUT) { - layer_create_msg_callback(my_data->report_data, report_flags, win32_debug_output_msg, NULL, &callback); - my_data->logging_callback.push_back(callback); - } - - if (!globalLockInitialized) - { - loader_platform_thread_create_mutex(&globalLock); - globalLockInitialized = 1; - } -} - -static const VkLayerProperties shader_checker_global_layers[] = { - { - "ShaderChecker", - VK_API_VERSION, - VK_MAKE_VERSION(0, 1, 0), - "Validation layer: ShaderChecker", - } -}; - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties( - const char *pLayerName, - uint32_t *pCount, - VkExtensionProperties* pProperties) -{ - /* shader checker does not have any global extensions */ - return util_GetExtensionProperties(0, NULL, pCount, pProperties); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( - uint32_t *pCount, - VkLayerProperties* pProperties) -{ - return util_GetLayerProperties(ARRAY_SIZE(shader_checker_global_layers), - shader_checker_global_layers, - pCount, pProperties); -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties( - VkPhysicalDevice physicalDevice, - const char* pLayerName, - uint32_t* pCount, - VkExtensionProperties* pProperties) -{ - /* Shader checker does not have any physical device extensions */ - 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) -{ - /* Shader checker physical device layers are the same as global */ - return util_GetLayerProperties(ARRAY_SIZE(shader_checker_global_layers), - shader_checker_global_layers, - pCount, pProperties); -} - -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"; - default: return "unknown"; - } -} - -/* returns ptr to null terminator */ -static char * -describe_type(char *dst, shader_module const *src, unsigned type) -{ - auto type_def_it = src->type_def_index.find(type); - - if (type_def_it == src->type_def_index.end()) { - return dst + sprintf(dst, "undef"); - } - - unsigned int const *code = (unsigned int const *)&src->words[type_def_it->second]; - unsigned opcode = code[0] & 0x0ffffu; - switch (opcode) { - case spv::OpTypeBool: - return dst + sprintf(dst, "bool"); - case spv::OpTypeInt: - return dst + sprintf(dst, "%cint%d", code[3] ? 's' : 'u', code[2]); - case spv::OpTypeFloat: - return dst + sprintf(dst, "float%d", code[2]); - case spv::OpTypeVector: - dst += sprintf(dst, "vec%d of ", code[3]); - return describe_type(dst, src, code[2]); - case spv::OpTypeMatrix: - dst += sprintf(dst, "mat%d of ", code[3]); - return describe_type(dst, src, code[2]); - case spv::OpTypeArray: - dst += sprintf(dst, "arr[%d] of ", code[3]); - return describe_type(dst, src, code[2]); - case spv::OpTypePointer: - dst += sprintf(dst, "ptr to %s ", storage_class_name(code[2])); - return describe_type(dst, src, code[3]); - case spv::OpTypeStruct: - { - unsigned oplen = code[0] >> 16; - dst += sprintf(dst, "struct of ("); - for (unsigned i = 2; i < oplen; i++) { - dst = describe_type(dst, src, code[i]); - dst += sprintf(dst, i == oplen-1 ? ")" : ", "); - } - return dst; - } - case spv::OpTypeSampler: - return dst + sprintf(dst, "sampler"); - 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) -{ - auto a_type_def_it = a->type_def_index.find(a_type); - auto b_type_def_it = b->type_def_index.find(b_type); - - if (a_type_def_it == a->type_def_index.end()) { - return false; - } - - if (b_type_def_it == b->type_def_index.end()) { - return false; - } - - /* walk two type trees together, and complain about differences */ - unsigned int const *a_code = (unsigned int const *)&a->words[a_type_def_it->second]; - unsigned int const *b_code = (unsigned int const *)&b->words[b_type_def_it->second]; - - unsigned a_opcode = a_code[0] & 0x0ffffu; - unsigned b_opcode = b_code[0] & 0x0ffffu; - - if (b_arrayed && b_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_code[2], false); - } - - if (a_opcode != b_opcode) { - return false; - } - - switch (a_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_code[2] == b_code[2] && a_code[3] == b_code[3] && !b_arrayed; - case spv::OpTypeFloat: - /* match on width */ - return a_code[2] == b_code[2] && !b_arrayed; - case spv::OpTypeVector: - case spv::OpTypeMatrix: - case spv::OpTypeArray: - /* 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_code[2], b_code[2], b_arrayed) && a_code[3] == b_code[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; - } - - unsigned a_len = a_code[0] >> 16; - unsigned b_len = b_code[0] >> 16; - - if (a_len != b_len) { - return false; /* structs cannot match if member counts differ */ - } - - for (unsigned i = 2; i < a_len; i++) { - if (!types_match(a, b, a_code[i], b_code[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_code[3], b_code[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 type_def_it = src->type_def_index.find(type); - - if (type_def_it == src->type_def_index.end()) { - return 1; /* This is actually broken SPIR-V... */ - } - - unsigned int const *code = (unsigned int const *)&src->words[type_def_it->second]; - unsigned opcode = code[0] & 0x0ffffu; - - switch (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, code[3], strip_array_level); - case spv::OpTypeArray: - if (strip_array_level) { - return get_locations_consumed_by_type(src, code[2], false); - } - else { - return code[3] * get_locations_consumed_by_type(src, code[2], false); - } - case spv::OpTypeMatrix: - /* num locations is the dimension * element size */ - return code[3] * get_locations_consumed_by_type(src, code[2], false); - default: - /* everything else is just 1. */ - return 1; - - /* TODO: extend to handle 64bit scalar types, whose vectors may need - * multiple locations. */ - } -} - - -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 void -collect_interface_by_location(layer_data *my_data, VkDevice dev, - shader_module const *src, spv::StorageClass sinterface, - std::map<uint32_t, interface_var> &out, - std::map<uint32_t, interface_var> &builtins_out, - bool is_array_of_verts) -{ - unsigned int const *code = (unsigned int const *)&src->words[0]; - size_t size = src->words.size(); - - std::unordered_map<unsigned, unsigned> var_locations; - std::unordered_map<unsigned, unsigned> var_builtins; - - unsigned word = 5; - while (word < size) { - - unsigned opcode = code[word] & 0x0ffffu; - unsigned oplen = (code[word] & 0xffff0000u) >> 16; - - /* We consider two interface models: SSO rendezvous-by-location, and - * builtins. Complain about anything that fits neither model. - */ - if (opcode == spv::OpDecorate) { - if (code[word+2] == spv::DecorationLocation) { - var_locations[code[word+1]] = code[word+3]; - } - - if (code[word+2] == spv::DecorationBuiltIn) { - var_builtins[code[word+1]] = code[word+3]; - } - } - - /* 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. */ - - if (opcode == spv::OpVariable && code[word+3] == sinterface) { - unsigned id = code[word+2]; - unsigned type = code[word+1]; - - int location = value_or_default(var_locations, code[word+2], -1); - int builtin = value_or_default(var_builtins, code[word+2], -1); - - if (location == -1 && builtin == -1) { - /* No location defined, and not bound to an API builtin. - * The spec says nothing about how this case works (or doesn't) - * for interface matching. - */ - log_msg(my_data->report_data, VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC", - "var %d (type %d) in %s interface has no Location or Builtin decoration", - code[word+2], code[word+1], storage_class_name(sinterface)); - } - else 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 (int offset = 0; offset < num_locations; offset++) { - interface_var v; - v.id = id; - v.type_id = type; - v.offset = offset; - out[location + offset] = v; - } - } - else { - /* A builtin interface variable */ - /* Note that since builtin interface variables do not consume numbered - * locations, there is no larger-than-vec4 consideration as above - */ - interface_var v; - v.id = id; - v.type_id = type; - v.offset = 0; - builtins_out[builtin] = v; - } - } - - word += oplen; - } -} - -static void -collect_interface_by_descriptor_slot(layer_data *my_data, VkDevice dev, - shader_module const *src, spv::StorageClass sinterface, - std::map<std::pair<unsigned, unsigned>, interface_var> &out) -{ - unsigned int const *code = (unsigned int const *)&src->words[0]; - size_t size = src->words.size(); - - std::unordered_map<unsigned, unsigned> var_sets; - std::unordered_map<unsigned, unsigned> var_bindings; - - unsigned word = 5; - while (word < size) { - - unsigned opcode = code[word] & 0x0ffffu; - unsigned oplen = (code[word] & 0xffff0000u) >> 16; - - /* All variables in the Uniform or UniformConstant storage classes are required to be decorated with both - * DecorationDescriptorSet and DecorationBinding. - */ - if (opcode == spv::OpDecorate) { - if (code[word+2] == spv::DecorationDescriptorSet) { - var_sets[code[word+1]] = code[word+3]; - } - - if (code[word+2] == spv::DecorationBinding) { - var_bindings[code[word+1]] = code[word+3]; - } - } - - if (opcode == spv::OpVariable && (code[word+3] == spv::StorageClassUniform || - code[word+3] == spv::StorageClassUniformConstant)) { - unsigned set = value_or_default(var_sets, code[word+2], 0); - unsigned binding = value_or_default(var_bindings, code[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_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, - SHADER_CHECKER_INCONSISTENT_SPIRV, "SC", - "var %d (type %d) in %s interface in descriptor slot (%u,%u) conflicts with existing definition", - code[word+2], code[word+1], storage_class_name(sinterface), - existing_it->first.first, existing_it->first.second); - } - - interface_var v; - v.id = code[word+2]; - v.type_id = code[word+1]; - out[std::make_pair(set, binding)] = v; - } - - word += oplen; - } -} - -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); - bool skip_call = false; - if (!shader_is_spirv(pCreateInfo)) { - skip_call |= log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, - /* dev */ 0, 0, SHADER_CHECKER_NON_SPIRV_SHADER, "SC", - "Shader is not SPIR-V"); - } - - if (skip_call) - return VK_ERROR_VALIDATION_FAILED; - - VkResult res = my_data->device_dispatch_table->CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule); - - if (res == VK_SUCCESS) { - loader_platform_thread_lock_mutex(&globalLock); - my_data->shader_module_map[*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) -{ - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkResult res = my_data->device_dispatch_table->CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass); - - loader_platform_thread_lock_mutex(&globalLock); - my_data->render_pass_map[*pRenderPass] = new render_pass(pCreateInfo); - loader_platform_thread_unlock_mutex(&globalLock); - return res; -} - -static bool -validate_interface_between_stages(layer_data *my_data, VkDevice dev, - shader_module const *producer, char const *producer_name, - shader_module const *consumer, char const *consumer_name, - bool consumer_arrayed_input) -{ - std::map<uint32_t, interface_var> outputs; - std::map<uint32_t, interface_var> inputs; - - std::map<uint32_t, interface_var> builtin_outputs; - std::map<uint32_t, interface_var> builtin_inputs; - - bool pass = true; - - collect_interface_by_location(my_data, dev, producer, spv::StorageClassOutput, outputs, builtin_outputs, false); - collect_interface_by_location(my_data, dev, consumer, spv::StorageClassInput, inputs, builtin_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 ? 0 : a_it->first; - auto b_first = b_at_end ? 0 : b_it->first; - - if (b_at_end || ((!a_at_end) && (a_first < b_first))) { - if (log_msg(my_data->report_data, VK_DBG_REPORT_PERF_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", - "%s writes to output location %d which is not consumed by %s", producer_name, a_first, consumer_name)) { - pass = false; - } - a_it++; - } - else if (a_at_end || a_first > b_first) { - if (log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", - "%s consumes input location %d which is not written by %s", consumer_name, b_first, 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_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", - "Type mismatch on location %d: '%s' vs '%s'", a_it->first, 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 type_def_it = src->type_def_index.find(type); - - if (type_def_it == src->type_def_index.end()) { - return FORMAT_TYPE_UNDEFINED; - } - - unsigned int const *code = (unsigned int const *)&src->words[type_def_it->second]; - unsigned opcode = code[0] & 0x0ffffu; - switch (opcode) { - case spv::OpTypeInt: - return code[3] ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT; - case spv::OpTypeFloat: - return FORMAT_TYPE_FLOAT; - case spv::OpTypeVector: - return get_fundamental_type(src, code[2]); - case spv::OpTypeMatrix: - return get_fundamental_type(src, code[2]); - case spv::OpTypeArray: - return get_fundamental_type(src, code[2]); - case spv::OpTypePointer: - return get_fundamental_type(src, code[3]); - default: - return FORMAT_TYPE_UNDEFINED; - } -} - - -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_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, 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) -{ - std::map<uint32_t, interface_var> inputs; - /* we collect builtin inputs, but they will never appear in the VI state -- - * the vs builtin inputs are generated in the pipeline, not sourced from buffers (VertexID, etc) - */ - std::map<uint32_t, interface_var> builtin_inputs; - bool pass = true; - - collect_interface_by_location(my_data, dev, vs, spv::StorageClassInput, inputs, builtin_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; - if (b_at_end || a_first < b_first) { - if (log_msg(my_data->report_data, VK_DBG_REPORT_PERF_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", - "Vertex attribute at location %d not consumed by VS", a_first)) { - pass = false; - } - it_a++; - } - else if (a_at_end || b_first < a_first) { - if (log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, 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_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, 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, render_pass const *rp, uint32_t subpass) -{ - const std::vector<VkFormat> &color_formats = rp->subpass_color_formats[subpass]; - std::map<uint32_t, interface_var> outputs; - std::map<uint32_t, interface_var> builtin_outputs; - bool pass = true; - - /* TODO: dual source blend index (spv::DecIndex, zero if not provided) */ - - collect_interface_by_location(my_data, dev, fs, spv::StorageClassOutput, outputs, builtin_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. - */ - - /* TODO: Figure out compile error with cb->attachmentCount */ - while ((outputs.size() > 0 && it != outputs.end()) || attachment < color_formats.size()) { - if (attachment == color_formats.size() || ( it != outputs.end() && it->first < attachment)) { - if (log_msg(my_data->report_data, VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", - "FS writes to output location %d with no matching attachment", it->first)) { - pass = false; - } - it++; - } - else if (it == outputs.end() || it->first > attachment) { - if (log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, 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_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, 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; -} - - -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 -has_descriptor_binding(std::vector<std::unordered_set<uint32_t>*>* layout, - std::pair<unsigned, unsigned> slot) -{ - if (!layout) - return false; - - if (slot.first >= layout->size()) - return false; - - auto set = (*layout)[slot.first]; - - return (set->find(slot.second) != set->end()); -} - -static uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) -{ - uint32_t bit_pos = u_ffs(stage); - return bit_pos-1; -} - -static bool -validate_graphics_pipeline(layer_data *my_data, VkDevice dev, VkGraphicsPipelineCreateInfo const *pCreateInfo) -{ - /* 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 geometry_stage = get_shader_stage_id(VK_SHADER_STAGE_GEOMETRY_BIT); - int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT); - - shader_module **shaders = new shader_module*[fragment_stage + 1]; /* exclude CS */ - memset(shaders, 0, sizeof(shader_module *) * (fragment_stage +1)); - render_pass const *rp = 0; - VkPipelineVertexInputStateCreateInfo const *vi = 0; - bool pass = true; - - loader_platform_thread_lock_mutex(&globalLock); - - 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_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_UNKNOWN_STAGE, "SC", - "Unknown shader stage %d", pStage->stage)) { - pass = false; - } - } - else { - shader_module *module = my_data->shader_module_map[pStage->module]; - shaders[get_shader_stage_id(pStage->stage)] = module; - - /* validate descriptor set layout against what the spirv module actually uses */ - std::map<std::pair<unsigned, unsigned>, interface_var> descriptor_uses; - collect_interface_by_descriptor_slot(my_data, dev, module, spv::StorageClassUniform, - descriptor_uses); - - auto layout = pCreateInfo->layout != VK_NULL_HANDLE ? - my_data->pipeline_layout_map[pCreateInfo->layout] : nullptr; - - for (auto it = descriptor_uses.begin(); it != descriptor_uses.end(); it++) { - - /* find the matching binding */ - auto found = has_descriptor_binding(layout, it->first); - - if (!found) { - char type_name[1024]; - describe_type(type_name, module, it->second.type_id); - if (log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, - 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 = false; - } - } - } - } - } - } - - if (pCreateInfo->renderPass != VK_NULL_HANDLE) - rp = my_data->render_pass_map[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]) && 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_GEOMETRY_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], shader_stage_attribs[producer].name, - shaders[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], rp, pCreateInfo->subpass) && pass; - } - - delete shaders; - - loader_platform_thread_unlock_mutex(&globalLock); - return pass; -} - -//TODO handle pipelineCache entry points -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkCreateGraphicsPipelines(VkDevice device, - VkPipelineCache pipelineCache, - uint32_t count, - const VkGraphicsPipelineCreateInfo *pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline *pPipelines) -{ - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - bool pass = true; - for (uint32_t i = 0; i < count; i++) { - pass = validate_graphics_pipeline(my_data, device, &pCreateInfos[i]) && pass; - } - - if (pass) { - /* The driver is allowed to crash if passed junk. Only actually create the - * pipeline if we didn't run into any showstoppers above. - */ - return my_data->device_dispatch_table->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines); - } - else { - return VK_ERROR_VALIDATION_FAILED; - } -} - - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) -{ - layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map); - VkResult result = my_device_data->device_dispatch_table->CreateDevice(gpu, pCreateInfo, pAllocator, pDevice); - if (result == VK_SUCCESS) { - layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map); - my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice); - } - return result; -} - -/* hook DextroyDevice to remove tableMap entry */ -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); - my_device_data->device_dispatch_table->DestroyDevice(device, pAllocator); - delete my_device_data->device_dispatch_table; - layer_data_map.erase(key); -} - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( - const VkInstanceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkInstance* pInstance) -{ - layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map); - VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; - VkResult result = pTable->CreateInstance(pCreateInfo, pAllocator, pInstance); - - if (result == VK_SUCCESS) { - layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map); - my_data->report_data = debug_report_create_instance( - pTable, - *pInstance, - pCreateInfo->enabledExtensionNameCount, - pCreateInfo->ppEnabledExtensionNames); - - init_shader_checker(my_data); - } - return result; -} - -/* hook DestroyInstance to remove tableInstanceMap entry */ -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator) -{ - dispatch_key key = get_dispatch_key(instance); - layer_data *my_data = get_my_data_ptr(key, layer_data_map); - my_data->instance_dispatch_table->DestroyInstance(instance, pAllocator); - - // Clean up logging callback, if any - while (my_data->logging_callback.size() > 0) { - VkDbgMsgCallback callback = my_data->logging_callback.back(); - layer_destroy_msg_callback(my_data->report_data, callback); - 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); - if (layer_data_map.empty()) { - // Release mutex when destroying last instance. - loader_platform_thread_delete_mutex(&globalLock); - globalLockInitialized = 0; - } -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkDbgCreateMsgCallback( - VkInstance instance, - VkFlags msgFlags, - const PFN_vkDbgMsgCallback pfnMsgCallback, - void* pUserData, - VkDbgMsgCallback* pMsgCallback) -{ - layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); - VkResult res = my_data->instance_dispatch_table->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback); - if (VK_SUCCESS == res) { - res = layer_create_msg_callback(my_data->report_data, msgFlags, pfnMsgCallback, pUserData, pMsgCallback); - } - return res; -} - -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkDbgDestroyMsgCallback( - VkInstance instance, - VkDbgMsgCallback msgCallback) -{ - layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); - VkResult res = my_data->instance_dispatch_table->DbgDestroyMsgCallback(instance, msgCallback); - layer_destroy_msg_callback(my_data->report_data, msgCallback); - return res; -} - -VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char* funcName) -{ - if (dev == NULL) - return NULL; - - layer_data *my_data; - /* loader uses this to force layer initialization; device object is wrapped */ - if (!strcmp("vkGetDeviceProcAddr", funcName)) { - VkBaseLayerObject* wrapped_dev = (VkBaseLayerObject*) dev; - my_data = get_my_data_ptr(get_dispatch_key(wrapped_dev->baseObject), layer_data_map); - my_data->device_dispatch_table = new VkLayerDispatchTable; - layer_initialize_dispatch_table(my_data->device_dispatch_table, wrapped_dev); - return (PFN_vkVoidFunction) vkGetDeviceProcAddr; - } - my_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map); - -#define ADD_HOOK(fn) \ - if (!strncmp(#fn, funcName, sizeof(#fn))) \ - return (PFN_vkVoidFunction) fn - - ADD_HOOK(vkCreateDevice); - ADD_HOOK(vkCreateShaderModule); - ADD_HOOK(vkCreateRenderPass); - ADD_HOOK(vkDestroyDevice); - ADD_HOOK(vkCreateGraphicsPipelines); - ADD_HOOK(vkCreateDescriptorSetLayout); - ADD_HOOK(vkCreatePipelineLayout); -#undef ADD_HOOK - - VkLayerDispatchTable* pTable = my_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) -{ - PFN_vkVoidFunction fptr; - - if (instance == NULL) - return NULL; - - layer_data *my_data; - if (!strcmp("vkGetInstanceProcAddr", funcName)) { - VkBaseLayerObject* wrapped_inst = (VkBaseLayerObject*) instance; - my_data = get_my_data_ptr(get_dispatch_key(wrapped_inst->baseObject), layer_data_map); - my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable; - layer_init_instance_dispatch_table(my_data->instance_dispatch_table, wrapped_inst); - return (PFN_vkVoidFunction) vkGetInstanceProcAddr; - } -#define ADD_HOOK(fn) \ - if (!strncmp(#fn, funcName, sizeof(#fn))) \ - return (PFN_vkVoidFunction) fn - - ADD_HOOK(vkCreateInstance); - ADD_HOOK(vkDestroyInstance); - ADD_HOOK(vkEnumerateInstanceExtensionProperties); - ADD_HOOK(vkEnumerateDeviceExtensionProperties); - ADD_HOOK(vkEnumerateInstanceLayerProperties); - ADD_HOOK(vkEnumerateDeviceLayerProperties); -#undef ADD_HOOK - - - 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); - } -} |
