| /* 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. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * Author: Jeremy Hayes <jeremy@lunarg.com> |
| * Author: Mark Lobodzinski <mark@lunarg.com> |
| * Author: Mike Stroyan <mike@LunarG.com> |
| * Author: Tobin Ehlis <tobin@lunarg.com> |
| */ |
| |
| // Allow use of STL min and max functions in Windows |
| #define NOMINMAX |
| |
| #include <algorithm> |
| #include <assert.h> |
| #include <cinttypes> |
| #include <memory> |
| #include <mutex> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <limits.h> |
| #include <unordered_map> |
| #include <vector> |
| #include <bitset> |
| #include <sstream> |
| |
| #include "vk_loader_platform.h" |
| #include "vk_dispatch_table_helper.h" |
| #include "vk_enum_string_helper.h" |
| #include "image.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_extension_utils.h" |
| #include "vk_layer_utils.h" |
| #include "vk_layer_logging.h" |
| #include "vk_validation_error_messages.h" |
| |
| using namespace std; |
| |
| namespace image { |
| |
| struct layer_data { |
| VkInstance instance; |
| |
| debug_report_data *report_data; |
| vector<VkDebugReportCallbackEXT> logging_callback; |
| VkLayerDispatchTable *device_dispatch_table; |
| VkLayerInstanceDispatchTable *instance_dispatch_table; |
| VkPhysicalDevice physicalDevice; |
| VkPhysicalDeviceProperties physicalDeviceProperties; |
| |
| unordered_map<VkImage, IMAGE_STATE> imageMap; |
| |
| layer_data() |
| : report_data(nullptr), |
| device_dispatch_table(nullptr), |
| instance_dispatch_table(nullptr), |
| physicalDevice(0), |
| physicalDeviceProperties(){}; |
| }; |
| |
| static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION; |
| |
| static unordered_map<void *, layer_data *> layer_data_map; |
| static std::mutex global_lock; |
| |
| static void init_image(layer_data *my_data, const VkAllocationCallbacks *pAllocator) { |
| layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_image"); |
| } |
| |
| static IMAGE_STATE const *getImageState(layer_data const *dev_data, VkImage image) { |
| auto it = dev_data->imageMap.find(image); |
| if (it == dev_data->imageMap.end()) { |
| return nullptr; |
| } |
| return &it->second; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance, |
| const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, |
| VkDebugReportCallbackEXT *pMsgCallback) { |
| layer_data *my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map); |
| VkResult res = my_data->instance_dispatch_table->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback); |
| if (res == VK_SUCCESS) { |
| res = layer_create_msg_callback(my_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback); |
| } |
| return res; |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback, |
| const VkAllocationCallbacks *pAllocator) { |
| layer_data *my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map); |
| my_data->instance_dispatch_table->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator); |
| layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator); |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(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 = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map); |
| my_data->instance_dispatch_table->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, |
| pMsg); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(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 = GetLayerDataPtr(get_dispatch_key(*pInstance), layer_data_map); |
| my_data->instance = *pInstance; |
| 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_image(my_data, pAllocator); |
| |
| return result; |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) { |
| // Grab the key before the instance is destroyed. |
| dispatch_key key = get_dispatch_key(instance); |
| layer_data *my_data = GetLayerDataPtr(key, layer_data_map); |
| VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; |
| pTable->DestroyInstance(instance, pAllocator); |
| |
| // 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); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) { |
| layer_data *my_instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map); |
| 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(my_instance_data->instance, "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(physicalDevice, pCreateInfo, pAllocator, pDevice); |
| if (result != VK_SUCCESS) { |
| return result; |
| } |
| |
| layer_data *my_device_data = GetLayerDataPtr(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); |
| my_device_data->physicalDevice = physicalDevice; |
| |
| my_instance_data->instance_dispatch_table->GetPhysicalDeviceProperties(physicalDevice, |
| &(my_device_data->physicalDeviceProperties)); |
| |
| return result; |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) { |
| dispatch_key key = get_dispatch_key(device); |
| layer_data *my_data = GetLayerDataPtr(key, layer_data_map); |
| my_data->device_dispatch_table->DestroyDevice(device, pAllocator); |
| delete my_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}}; |
| |
| static const VkLayerProperties global_layer = { |
| "VK_LAYER_LUNARG_image", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer", |
| }; |
| |
| // Start of the Image layer proper |
| |
| VKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, VkImage *pImage) { |
| VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; |
| layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); |
| |
| result = device_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage); |
| |
| if (result == VK_SUCCESS) { |
| std::lock_guard<std::mutex> lock(global_lock); |
| device_data->imageMap[*pImage] = IMAGE_STATE(pCreateInfo); |
| } |
| return result; |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) { |
| layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); |
| std::unique_lock<std::mutex> lock(global_lock); |
| device_data->imageMap.erase(image); |
| lock.unlock(); |
| device_data->device_dispatch_table->DestroyImage(device, image, pAllocator); |
| } |
| |
| static bool ValidateBufferImageCopyData(layer_data *dev_data, uint32_t regionCount, const VkBufferImageCopy *pRegions, |
| VkImage image, const char *function) { |
| bool skip = false; |
| |
| for (uint32_t i = 0; i < regionCount; i++) { |
| auto image_info = getImageState(dev_data, image); |
| if (image_info) { |
| if ((image_info->imageType == VK_IMAGE_TYPE_1D) || (image_info->imageType == VK_IMAGE_TYPE_2D)) { |
| if ((pRegions[i].imageOffset.z != 0) || (pRegions[i].imageExtent.depth != 1)) { |
| skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, |
| reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01269, "IMAGE", |
| "%s(): pRegion[%d] imageOffset.z is %d and imageExtent.depth is %d. These must be 0 and 1, " |
| "respectively. %s", |
| function, i, pRegions[i].imageOffset.z, pRegions[i].imageExtent.depth, |
| validation_error_map[VALIDATION_ERROR_01269]); |
| } |
| } |
| |
| // If the the calling command's VkImage parameter's format is not a depth/stencil format, |
| // then bufferOffset must be a multiple of the calling command's VkImage parameter's texel size |
| auto texel_size = vk_format_get_size(image_info->format); |
| if (!vk_format_is_depth_and_stencil(image_info->format) && vk_safe_modulo(pRegions[i].bufferOffset, texel_size) != 0) { |
| skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, |
| reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01263, "IMAGE", |
| "%s(): pRegion[%d] bufferOffset 0x%" PRIxLEAST64 |
| " must be a multiple of this format's texel size (" PRINTF_SIZE_T_SPECIFIER "). %s", |
| function, i, pRegions[i].bufferOffset, texel_size, validation_error_map[VALIDATION_ERROR_01263]); |
| } |
| |
| // BufferOffset must be a multiple of 4 |
| if (vk_safe_modulo(pRegions[i].bufferOffset, 4) != 0) { |
| skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, |
| reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01264, "IMAGE", |
| "%s(): pRegion[%d] bufferOffset 0x%" PRIxLEAST64 " must be a multiple of 4. %s", function, i, |
| pRegions[i].bufferOffset, validation_error_map[VALIDATION_ERROR_01264]); |
| } |
| |
| // BufferRowLength must be 0, or greater than or equal to the width member of imageExtent |
| if ((pRegions[i].bufferRowLength != 0) && (pRegions[i].bufferRowLength < pRegions[i].imageExtent.width)) { |
| skip |= log_msg( |
| dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, |
| reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01265, "IMAGE", |
| "%s(): pRegion[%d] bufferRowLength (%d) must be zero or greater-than-or-equal-to imageExtent.width (%d). %s", |
| function, i, pRegions[i].bufferRowLength, pRegions[i].imageExtent.width, |
| validation_error_map[VALIDATION_ERROR_01265]); |
| } |
| |
| // BufferImageHeight must be 0, or greater than or equal to the height member of imageExtent |
| if ((pRegions[i].bufferImageHeight != 0) && (pRegions[i].bufferImageHeight < pRegions[i].imageExtent.height)) { |
| skip |= log_msg( |
| dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, |
| reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01266, "IMAGE", |
| "%s(): pRegion[%d] bufferImageHeight (%d) must be zero or greater-than-or-equal-to imageExtent.height (%d). %s", |
| function, i, pRegions[i].bufferImageHeight, pRegions[i].imageExtent.height, |
| validation_error_map[VALIDATION_ERROR_01266]); |
| } |
| |
| const int num_bits = sizeof(VkFlags) * CHAR_BIT; |
| std::bitset<num_bits> aspect_mask_bits(pRegions[i].imageSubresource.aspectMask); |
| if (aspect_mask_bits.count() != 1) { |
| skip |= |
| log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, |
| reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01280, "IMAGE", |
| "%s: aspectMasks for imageSubresource in each region must have only a single bit set. %s", function, |
| validation_error_map[VALIDATION_ERROR_01280]); |
| } |
| } |
| } |
| |
| return skip; |
| } |
| |
| static bool PreCallValidateCmdCopyImageToBuffer(layer_data *dev_data, VkImage srcImage, uint32_t regionCount, |
| const VkBufferImageCopy *pRegions, const char *func_name) { |
| return ValidateBufferImageCopyData(dev_data, regionCount, pRegions, srcImage, "vkCmdCopyImageToBuffer"); |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, |
| VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) { |
| layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map); |
| |
| if (!PreCallValidateCmdCopyImageToBuffer(device_data, srcImage, regionCount, pRegions, "vkCmdCopyImageToBuffer()")) { |
| device_data->device_dispatch_table->CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, |
| pRegions); |
| } |
| } |
| |
| static bool PreCallValidateCmdCopyBufferToImage(layer_data *dev_data, VkImage dstImage, uint32_t regionCount, |
| const VkBufferImageCopy *pRegions, const char *func_name) { |
| return ValidateBufferImageCopyData(dev_data, regionCount, pRegions, dstImage, "vkCmdCopyBufferToImage"); |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, |
| VkImageLayout dstImageLayout, uint32_t regionCount, |
| const VkBufferImageCopy *pRegions) { |
| layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map); |
| |
| if (!PreCallValidateCmdCopyBufferToImage(device_data, dstImage, regionCount, pRegions, "vkCmdCopyBufferToImage()")) { |
| device_data->device_dispatch_table->CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, |
| pRegions); |
| } |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties) { |
| layer_data *phy_dev_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map); |
| phy_dev_data->instance_dispatch_table->GetPhysicalDeviceProperties(physicalDevice, pProperties); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) { |
| return util_GetLayerProperties(1, &global_layer, pCount, pProperties); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, |
| VkLayerProperties *pProperties) { |
| return util_GetLayerProperties(1, &global_layer, pCount, pProperties); |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, |
| VkExtensionProperties *pProperties) { |
| if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) |
| return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties); |
| |
| return VK_ERROR_LAYER_NOT_PRESENT; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName, |
| uint32_t *pCount, VkExtensionProperties *pProperties) { |
| // Image does not have any physical device extensions |
| if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties); |
| |
| assert(physicalDevice); |
| |
| dispatch_key key = get_dispatch_key(physicalDevice); |
| layer_data *my_data = GetLayerDataPtr(key, layer_data_map); |
| VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; |
| return pTable->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties); |
| } |
| |
| static PFN_vkVoidFunction intercept_core_instance_command(const char *name); |
| static PFN_vkVoidFunction intercept_core_device_command(const char *name); |
| |
| VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) { |
| PFN_vkVoidFunction proc = intercept_core_device_command(funcName); |
| if (proc) return proc; |
| |
| assert(device); |
| |
| layer_data *my_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); |
| |
| VkLayerDispatchTable *pTable = my_data->device_dispatch_table; |
| { |
| if (pTable->GetDeviceProcAddr == NULL) return NULL; |
| return pTable->GetDeviceProcAddr(device, funcName); |
| } |
| } |
| |
| VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) { |
| PFN_vkVoidFunction proc = intercept_core_instance_command(funcName); |
| if (!proc) proc = intercept_core_device_command(funcName); |
| if (proc) return proc; |
| |
| assert(instance); |
| layer_data *my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map); |
| |
| proc = debug_report_get_instance_proc_addr(my_data->report_data, funcName); |
| if (proc) return proc; |
| |
| VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; |
| if (pTable->GetInstanceProcAddr == NULL) return NULL; |
| return pTable->GetInstanceProcAddr(instance, funcName); |
| } |
| |
| VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) { |
| assert(instance); |
| |
| layer_data *my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map); |
| |
| VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table; |
| if (pTable->GetPhysicalDeviceProcAddr == NULL) return NULL; |
| return pTable->GetPhysicalDeviceProcAddr(instance, funcName); |
| } |
| |
| static PFN_vkVoidFunction intercept_core_instance_command(const char *name) { |
| static const struct { |
| const char *name; |
| PFN_vkVoidFunction proc; |
| } core_instance_commands[] = { |
| {"vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr)}, |
| {"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance)}, |
| {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)}, |
| {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice)}, |
| {"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties)}, |
| {"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties)}, |
| {"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties)}, |
| {"vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties)}, |
| {"vkGetPhysicalDeviceProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProperties)}, |
| {"vk_layerGetPhysicalDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProcAddr)}, |
| }; |
| |
| for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++) { |
| if (!strcmp(core_instance_commands[i].name, name)) return core_instance_commands[i].proc; |
| } |
| |
| return nullptr; |
| } |
| |
| static PFN_vkVoidFunction intercept_core_device_command(const char *name) { |
| static const struct { |
| const char *name; |
| PFN_vkVoidFunction proc; |
| } core_device_commands[] = { |
| {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)}, |
| {"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice)}, |
| {"vkCreateImage", reinterpret_cast<PFN_vkVoidFunction>(CreateImage)}, |
| {"vkDestroyImage", reinterpret_cast<PFN_vkVoidFunction>(DestroyImage)}, |
| {"vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer)}, |
| {"vkCmdCopyBufferToImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBufferToImage)}, |
| }; |
| |
| for (size_t i = 0; i < ARRAY_SIZE(core_device_commands); i++) { |
| if (!strcmp(core_device_commands[i].name, name)) return core_device_commands[i].proc; |
| } |
| |
| return nullptr; |
| } |
| |
| } // namespace image |
| |
| // vk_layer_logging.h expects these to be defined |
| |
| VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance, |
| const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, |
| VkDebugReportCallbackEXT *pMsgCallback) { |
| return image::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback); |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback, |
| const VkAllocationCallbacks *pAllocator) { |
| image::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator); |
| } |
| |
| 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) { |
| image::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg); |
| } |
| |
| // loader-layer interface v0, just wrappers since there is only a layer |
| |
| VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, |
| VkExtensionProperties *pProperties) { |
| return image::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount, |
| VkLayerProperties *pProperties) { |
| return image::EnumerateInstanceLayerProperties(pCount, pProperties); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, |
| VkLayerProperties *pProperties) { |
| // the layer command handles VK_NULL_HANDLE just fine internally |
| assert(physicalDevice == VK_NULL_HANDLE); |
| return image::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, |
| const char *pLayerName, uint32_t *pCount, |
| VkExtensionProperties *pProperties) { |
| // the layer command handles VK_NULL_HANDLE just fine internally |
| assert(physicalDevice == VK_NULL_HANDLE); |
| return image::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) { |
| return image::GetDeviceProcAddr(dev, funcName); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) { |
| return image::GetInstanceProcAddr(instance, funcName); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, |
| const char *funcName) { |
| return image::GetPhysicalDeviceProcAddr(instance, funcName); |
| } |
| |
| VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) { |
| assert(pVersionStruct != NULL); |
| assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT); |
| |
| // Fill in the function pointers if our version is at least capable of having the structure contain them. |
| if (pVersionStruct->loaderLayerInterfaceVersion >= 2) { |
| pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr; |
| pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr; |
| pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr; |
| } |
| |
| if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) { |
| image::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion; |
| } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) { |
| pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION; |
| } |
| |
| return VK_SUCCESS; |
| } |