From 5b36b809a38d589d4683f58b0fa13ca31b26b21e Mon Sep 17 00:00:00 2001 From: Jeremy Hayes Date: Thu, 18 Jun 2015 10:12:39 -0600 Subject: [PATCH] layers: Move image validation to separate layer. --- layers/CMakeLists.txt | 1 + layers/image.cpp | 468 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 469 insertions(+) create mode 100644 layers/image.cpp diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt index 461d2516..a71931dc 100644 --- a/layers/CMakeLists.txt +++ b/layers/CMakeLists.txt @@ -100,6 +100,7 @@ add_vk_layer(Multi multi.cpp) add_vk_layer(DrawState draw_state.cpp layers_debug_marker_table.cpp layers_table.cpp) add_vk_layer(MemTracker mem_tracker.cpp layers_table.cpp) add_vk_layer(ShaderChecker shader_checker.cpp layers_table.cpp) +add_vk_layer(Image image.cpp layers_table.cpp) # generated add_vk_layer(Generic generic_layer.cpp layers_table.cpp) add_vk_layer(APIDump api_dump.cpp layers_table.cpp) diff --git a/layers/image.cpp b/layers/image.cpp new file mode 100644 index 00000000..cac66a5a --- /dev/null +++ b/layers/image.cpp @@ -0,0 +1,468 @@ +/* + * Vulkan + * + * Copyright (C) 2014 LunarG, Inc. + * + * 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. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "loader_platform.h" +#include "vkLayer.h" +#include "layers_config.h" +#include "vk_enum_validate_helper.h" +#include "vk_struct_validate_helper.h" +//The following is #included again to catch certain OS-specific functions being used: +#include "loader_platform.h" + +#include "layers_table.h" +#include "layer_data.h" +#include "layer_logging.h" + +typedef struct _layer_data { + debug_report_data *report_data; + VkDbgMsgCallback logging_callback; +} layer_data; + +static std::unordered_map layer_data_map; +static device_table_map image_device_table_map; +static instance_table_map image_instance_table_map; + +// "my device data" +debug_report_data *mdd(VkObject object) +{ + dispatch_key key = get_dispatch_key(object); + layer_data *data = get_my_data_ptr(key, layer_data_map); +#if DISPATCH_MAP_DEBUG + fprintf(stderr, "MDD: map: %p, object: %p, key: %p, data: %p\n", &layer_data_map, object, key, data); +#endif + assert(data->report_data != NULL); + return data->report_data; +} + +// "my instance data" +debug_report_data *mid(VkInstance object) +{ + dispatch_key key = get_dispatch_key(object); + layer_data *data = get_my_data_ptr(get_dispatch_key(object), layer_data_map); +#if DISPATCH_MAP_DEBUG + fprintf(stderr, "MID: map: %p, object: %p, key: %p, data: %p\n", &layer_data_map, object, key, data); +#endif + assert(data->report_data != NULL); + return data->report_data; +} + +static void InitImage(layer_data *data) +{ + uint32_t report_flags = getLayerOptionFlags("ImageReportFlags", 0); + + uint32_t debug_action = 0; + getLayerOptionEnum("ImageDebugAction", (uint32_t *) &debug_action); + if(debug_action & VK_DBG_LAYER_ACTION_LOG_MSG) + { + FILE *log_output = NULL; + const char* option_str = getLayerOption("ImageLogFilename"); + if(option_str) + { + log_output = fopen(option_str, "w"); + } + if(log_output == NULL) + { + log_output = stdout; + } + + layer_create_msg_callback(data->report_data, report_flags, log_callback, (void*)log_output, &data->logging_callback); + } +} + +VK_LAYER_EXPORT VkResult VKAPI vkDbgCreateMsgCallback( + VkInstance instance, + VkFlags msgFlags, + const PFN_vkDbgMsgCallback pfnMsgCallback, + void* pUserData, + VkDbgMsgCallback* pMsgCallback) +{ + VkLayerInstanceDispatchTable *pTable = get_dispatch_table(image_instance_table_map, instance); + VkResult res = pTable->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback); + if (res == VK_SUCCESS) { + layer_data *data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); + + res = layer_create_msg_callback(data->report_data, msgFlags, pfnMsgCallback, pUserData, pMsgCallback); + } + return res; +} + +VK_LAYER_EXPORT VkResult VKAPI vkDbgDestroyMsgCallback( + VkInstance instance, + VkDbgMsgCallback msgCallback) +{ + VkLayerInstanceDispatchTable *pTable = get_dispatch_table(image_instance_table_map, instance); + VkResult res = pTable->DbgDestroyMsgCallback(instance, msgCallback); + + layer_data *data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); + layer_destroy_msg_callback(data->report_data, msgCallback); + + return res; +} + +VK_LAYER_EXPORT VkResult VKAPI vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, VkInstance* pInstance) +{ + VkLayerInstanceDispatchTable *pTable = get_dispatch_table(image_instance_table_map, *pInstance); + VkResult result = pTable->CreateInstance(pCreateInfo, pInstance); + + if (result == VK_SUCCESS) { + layer_data *data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map); + data->report_data = debug_report_create_instance(pTable, *pInstance, pCreateInfo->extensionCount, + pCreateInfo->pEnabledExtensions); + + InitImage(data); + } + + return result; +} + +VK_LAYER_EXPORT VkResult VKAPI vkDestroyInstance(VkInstance instance) +{ + // Grab the key before the instance is destroyed. + dispatch_key key = get_dispatch_key(instance); + VkLayerInstanceDispatchTable *pTable = get_dispatch_table(image_instance_table_map, instance); + VkResult result = pTable->DestroyInstance(instance); + + // Clean up logging callback, if any + layer_data *data = get_my_data_ptr(key, layer_data_map); + if(data->logging_callback) + { + layer_destroy_msg_callback(data->report_data, data->logging_callback); + } + + layer_debug_report_destroy_instance(mid(instance)); + layer_data_map.erase(pTable); + + image_instance_table_map.erase(key); + assert(image_instance_table_map.size() == 0 && "Should not have any instance mappings hanging around"); + + return result; +} + +VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice) +{ + VkLayerInstanceDispatchTable *pTable = get_dispatch_table(image_instance_table_map, physicalDevice); + VkResult result = pTable->CreateDevice(physicalDevice, pCreateInfo, pDevice); + if(result == VK_SUCCESS) + { + layer_data *instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map); + layer_data *device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map); + device_data->report_data = layer_debug_report_create_device(instance_data->report_data, *pDevice); + } + + return result; +} + +VK_LAYER_EXPORT VkResult VKAPI vkDestroyDevice(VkDevice device) +{ + layer_debug_report_destroy_device(device); + + dispatch_key key = get_dispatch_key(device); +#if DISPATCH_MAP_DEBUG + fprintf(stderr, "Device: %p, key: %p\n", device, key); +#endif + + VkResult result = get_dispatch_table(image_device_table_map, device)->DestroyDevice(device); + image_device_table_map.erase(key); + assert(image_device_table_map.size() == 0 && "Should not have any instance mappings hanging around"); + + return result; +} + +#define IMAGE_LAYER_EXT_ARRAY_SIZE 2 +static const VkExtensionProperties pcExts[IMAGE_LAYER_EXT_ARRAY_SIZE] = { + { + VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES, + "Image", + 0x10, + "Sample layer: Image", + }, + { + VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES, + "Validation", + 0x10, + "Sample layer: Image", + } +}; + +VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo( + VkExtensionInfoType infoType, + uint32_t extensionIndex, + size_t* pDataSize, + void* pData) +{ + /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */ + uint32_t *count = NULL; + + if (pDataSize == NULL) + { + return VK_ERROR_INVALID_POINTER; + } + + switch (infoType) { + case VK_EXTENSION_INFO_TYPE_COUNT: + *pDataSize = sizeof(uint32_t); + if (pData == NULL) + return VK_SUCCESS; + count = (uint32_t *) pData; + *count = IMAGE_LAYER_EXT_ARRAY_SIZE; + break; + case VK_EXTENSION_INFO_TYPE_PROPERTIES: + *pDataSize = sizeof(VkExtensionProperties); + if (pData == NULL) + return VK_SUCCESS; + if (extensionIndex >= IMAGE_LAYER_EXT_ARRAY_SIZE) + return VK_ERROR_INVALID_VALUE; + memcpy((VkExtensionProperties *) pData, &pcExts[extensionIndex], sizeof(VkExtensionProperties)); + break; + default: + return VK_ERROR_INVALID_VALUE; + }; + + return VK_SUCCESS; +} + +VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceExtensionInfo( + VkPhysicalDevice gpu, + VkExtensionInfoType infoType, + uint32_t extensionIndex, + size_t* pDataSize, + void* pData) +{ + /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */ + uint32_t *count = NULL; + + if (pDataSize == NULL) + { + return VK_ERROR_INVALID_POINTER; + } + + switch (infoType) { + case VK_EXTENSION_INFO_TYPE_COUNT: + *pDataSize = sizeof(uint32_t); + if (pData == NULL) + return VK_SUCCESS; + count = (uint32_t *) pData; + *count = IMAGE_LAYER_EXT_ARRAY_SIZE; + break; + case VK_EXTENSION_INFO_TYPE_PROPERTIES: + *pDataSize = sizeof(VkExtensionProperties); + if (pData == NULL) + return VK_SUCCESS; + if (extensionIndex >= IMAGE_LAYER_EXT_ARRAY_SIZE) + return VK_ERROR_INVALID_VALUE; + memcpy((VkExtensionProperties *) pData, &pcExts[extensionIndex], sizeof(VkExtensionProperties)); + break; + default: + return VK_ERROR_INVALID_VALUE; + }; + + return VK_SUCCESS; +} + +VK_LAYER_EXPORT VkResult VKAPI vkCreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, VkImage* pImage) +{ + if(pCreateInfo->format != VK_FORMAT_UNDEFINED) + { + VkFormatProperties properties; + size_t size = sizeof(properties); + VkResult result = get_dispatch_table(image_device_table_map, device)->GetFormatInfo(device, pCreateInfo->format, + VK_FORMAT_INFO_TYPE_PROPERTIES, &size, &properties); + if(result != VK_SUCCESS) + { + char const str[] = "vkCreateImage parameter, VkFormat pCreateInfo->format, cannot be validated"; + log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str); + } + + if((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0)) + { + char const str[] = "vkCreateImage parameter, VkFormat pCreateInfo->format, contains unsupported format"; + log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str); + } + } + + VkResult result = get_dispatch_table(image_device_table_map, device)->CreateImage(device, pCreateInfo, pImage); + + return result; +} + +VK_LAYER_EXPORT VkResult VKAPI vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, VkRenderPass* pRenderPass) +{ + for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i) + { + if(pCreateInfo->pColorFormats[i] != VK_FORMAT_UNDEFINED) + { + VkFormatProperties properties; + size_t size = sizeof(properties); + VkResult result = get_dispatch_table(image_device_table_map, device)->GetFormatInfo(device, pCreateInfo->pColorFormats[i], + VK_FORMAT_INFO_TYPE_PROPERTIES, &size, &properties); + if(result != VK_SUCCESS) + { + std::stringstream ss; + ss << "vkCreateRenderPass parameter, VkFormat pCreateInfo->pColorFormats[" << i << "], cannot be validated"; + log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str()); + continue; + } + + if((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0)) + { + std::stringstream ss; + ss << "vkCreateRenderPass parameter, VkFormat pCreateInfo->pColorFormats[" << i << "], contains unsupported format"; + log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str()); + } + } + } + + for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i) + { + if(!validate_VkImageLayout(pCreateInfo->pColorLayouts[i])) + { + std::stringstream ss; + ss << "vkCreateRenderPass parameter, VkImageLayout pCreateInfo->pColorLayouts[" << i << "], is unrecognized"; + log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str()); + } + } + + for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i) + { + if(!validate_VkAttachmentLoadOp(pCreateInfo->pColorLoadOps[i])) + { + std::stringstream ss; + ss << "vkCreateRenderPass parameter, VkAttachmentLoadOp pCreateInfo->pColorLoadOps[" << i << "], is unrecognized"; + log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str()); + } + } + + for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i) + { + if(!validate_VkAttachmentStoreOp(pCreateInfo->pColorStoreOps[i])) + { + std::stringstream ss; + ss << "vkCreateRenderPass parameter, VkAttachmentStoreOp pCreateInfo->pColorStoreOps[" << i << "], is unrecognized"; + log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str()); + } + } + + for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i) + { + if(!vk_validate_vkclearcolor(&(pCreateInfo->pColorLoadClearValues[i]))) + { + std::stringstream ss; + ss << "vkCreateRenderPass parameter, VkClearColor pCreateInfo->pColorLoadClearValues[" << i << "], is invalid"; + log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str()); + } + } + + if(pCreateInfo->depthStencilFormat != VK_FORMAT_UNDEFINED) + { + VkFormatProperties properties; + size_t size = sizeof(properties); + VkResult result = get_dispatch_table(image_device_table_map, device)->GetFormatInfo(device, pCreateInfo->depthStencilFormat, + VK_FORMAT_INFO_TYPE_PROPERTIES, &size, &properties); + if(result != VK_SUCCESS) + { + char const str[] = "vkCreateRenderPass parameter, VkFormat pCreateInfo->depthStencilFormat, cannot be validated"; + log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str); + } + + if((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0)) + { + char const str[] = "vkCreateRenderPass parameter, VkFormat pCreateInfo->depthStencilFormat, contains unsupported format"; + log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str); + } + } + + VkResult result = get_dispatch_table(image_device_table_map, device)->CreateRenderPass(device, pCreateInfo, pRenderPass); + + return result; +} + +VK_LAYER_EXPORT void* VKAPI vkGetDeviceProcAddr(VkDevice device, const char* funcName) +{ + if (device == NULL) { + return NULL; + } + + /* loader uses this to force layer initialization; device object is wrapped */ + if (!strcmp(funcName, "vkGetDeviceProcAddr")) { + initDeviceTable(image_device_table_map, (const VkBaseLayerObject *) device); + return (void*) vkGetDeviceProcAddr; + } + + if (!strcmp(funcName, "vkDestroyDevice")) + return (void*) vkDestroyDevice; + if (!strcmp(funcName, "vkCreateImage")) + return (void*) vkCreateImage; + if (!strcmp(funcName, "vkCreateRenderPass")) + return (void*) vkCreateRenderPass; + + { + if (get_dispatch_table(image_device_table_map, device)->GetDeviceProcAddr == NULL) + return NULL; + return get_dispatch_table(image_device_table_map, device)->GetDeviceProcAddr(device, funcName); + } +} + +VK_LAYER_EXPORT void* VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* funcName) +{ + if (instance == NULL) { + return NULL; + } + + /* loader uses this to force layer initialization; instance object is wrapped */ + if (!strcmp(funcName, "vkGetInstanceProcAddr")) { + initInstanceTable(image_instance_table_map, (const VkBaseLayerObject *) instance); + return (void *) vkGetInstanceProcAddr; + } + + if (!strcmp(funcName, "vkCreateInstance")) + return (void*) vkCreateInstance; + if (!strcmp(funcName, "vkDestroyInstance")) + return (void *) vkDestroyInstance; + if (!strcmp(funcName, "vkCreateDevice")) + return (void*) vkCreateDevice; + if (!strcmp(funcName, "vkGetGlobalExtensionInfo")) + return (void*) vkGetGlobalExtensionInfo; + if (!strcmp(funcName, "vkGetPhysicalDeviceExtensionInfo")) + return (void*) vkGetPhysicalDeviceExtensionInfo; + + layer_data *data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map); + void* fptr = debug_report_get_instance_proc_addr(data->report_data, funcName); + if(fptr) + return fptr; + + { + if (get_dispatch_table(image_instance_table_map, instance)->GetInstanceProcAddr == NULL) + return NULL; + return get_dispatch_table(image_instance_table_map, instance)->GetInstanceProcAddr(instance, funcName); + } +} -- 2.34.1