1/* 2 * 3 * Copyright (C) 2017 Valve Corporation 4 * Copyright (C) 2017 LunarG, Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * Author: Arda Coskunses <arda@lunarg.com> 19 * Author: Tony Barbour <tony@LunarG.com> 20 */ 21#include <string.h> 22#include <stdlib.h> 23#include <assert.h> 24#include <unordered_map> 25 26#include "vk_dispatch_table_helper.h" 27#include "vk_lunarg_device_profile_api_layer.h" 28#include "vk_device_profile_api_layer.h" 29#include "threading.h" 30 31namespace device_profile_api { 32 33static std::unordered_map<dispatch_key, VkInstance> device_profile_api_instance_map; 34static std::mutex global_lock; 35 36static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION; 37 38struct device_data { 39 VkInstance instance; 40 VkPhysicalDeviceProperties phy_device_props; 41 std::unordered_map<VkFormat, VkFormatProperties, std::hash<int> > format_properties_map; 42}; 43 44static std::unordered_map<VkPhysicalDevice, struct device_data> device_profile_api_dev_data_map; 45 46// device_profile_api Layer EXT APIs 47typedef void(VKAPI_PTR *PFN_vkGetOriginalPhysicalDeviceLimitsEXT)(VkPhysicalDevice physicalDevice, 48 const VkPhysicalDeviceLimits *limits); 49typedef void(VKAPI_PTR *PFN_vkSetPhysicalDeviceLimitsEXT)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceLimits *newLimits); 50typedef void(VKAPI_PTR *PFN_vkGetOriginalPhysicalDeviceFormatPropertiesEXT)(VkPhysicalDevice physicalDevice, VkFormat format, 51 const VkFormatProperties *properties); 52typedef void(VKAPI_PTR *PFN_vkSetPhysicalDeviceFormatPropertiesEXT)(VkPhysicalDevice physicalDevice, VkFormat format, 53 const VkFormatProperties newProperties); 54 55VKAPI_ATTR void VKAPI_CALL GetOriginalPhysicalDeviceLimitsEXT(VkPhysicalDevice physicalDevice, VkPhysicalDeviceLimits *orgLimits) { 56 std::lock_guard<std::mutex> lock(global_lock); 57 auto device_profile_api_data_it = device_profile_api_dev_data_map.find(physicalDevice); 58 if (device_profile_api_data_it != device_profile_api_dev_data_map.end()) { 59 layer_data *device_profile_data = GetLayerDataPtr(get_dispatch_key(device_profile_api_dev_data_map[physicalDevice].instance), layer_data_map); 60 61 VkPhysicalDeviceProperties props; 62 device_profile_data->instance_dispatch_table 63 ->GetPhysicalDeviceProperties(physicalDevice, &props); 64 memcpy(orgLimits, &props.limits, sizeof(VkPhysicalDeviceLimits)); 65 } 66} 67 68VKAPI_ATTR void VKAPI_CALL SetPhysicalDeviceLimitsEXT(VkPhysicalDevice physicalDevice, 69 const VkPhysicalDeviceLimits *newLimits) { 70 std::lock_guard<std::mutex> lock(global_lock); 71 72 // search if we got the device limits for this device and stored in device_profile_api layer 73 auto device_profile_api_data_it = device_profile_api_dev_data_map.find(physicalDevice); 74 if (device_profile_api_data_it != device_profile_api_dev_data_map.end()) { 75 memcpy(&(device_profile_api_dev_data_map[physicalDevice].phy_device_props.limits), newLimits, sizeof(VkPhysicalDeviceLimits)); 76 } 77} 78 79VKAPI_ATTR void VKAPI_CALL GetOriginalPhysicalDeviceFormatPropertiesEXT(VkPhysicalDevice physicalDevice, VkFormat format, 80 VkFormatProperties *properties) { 81 std::lock_guard<std::mutex> lock(global_lock); 82 auto device_profile_api_data_it = device_profile_api_dev_data_map.find(physicalDevice); 83 if (device_profile_api_data_it != device_profile_api_dev_data_map.end()) { 84 layer_data *device_profile_data = 85 GetLayerDataPtr(get_dispatch_key(device_profile_api_dev_data_map[physicalDevice].instance), layer_data_map); 86 device_profile_data->instance_dispatch_table->GetPhysicalDeviceFormatProperties(physicalDevice, format, properties); 87 } 88} 89 90VKAPI_ATTR void VKAPI_CALL SetPhysicalDeviceFormatPropertiesEXT(VkPhysicalDevice physicalDevice, VkFormat format, 91 const VkFormatProperties newProperties) { 92 std::lock_guard<std::mutex> lock(global_lock); 93 94 // search if we got the device limits for this device and stored in device_profile_api layer 95 auto device_profile_api_data_it = device_profile_api_dev_data_map.find(physicalDevice); 96 if (device_profile_api_data_it != device_profile_api_dev_data_map.end()) { 97 memcpy(&(device_profile_api_dev_data_map[physicalDevice].format_properties_map[format]), &newProperties, 98 sizeof(VkFormatProperties)); 99 } 100} 101 102VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, 103 VkInstance *pInstance) { 104 VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); 105 std::lock_guard<std::mutex> lock(global_lock); 106 107 assert(chain_info->u.pLayerInfo); 108 PFN_vkGetInstanceProcAddr fp_get_instance_proc_addr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; 109 PFN_vkCreateInstance fp_create_instance = (PFN_vkCreateInstance)fp_get_instance_proc_addr(NULL, "vkCreateInstance"); 110 if (fp_create_instance == NULL) return VK_ERROR_INITIALIZATION_FAILED; 111 112 // Advance the link info for the next element on the chain 113 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; 114 115 VkResult result = fp_create_instance(pCreateInfo, pAllocator, pInstance); 116 if (result != VK_SUCCESS) return result; 117 118 device_profile_api_instance_map[get_dispatch_key(*pInstance)] = *pInstance; 119 initInstanceTable(*pInstance, fp_get_instance_proc_addr); 120 121 layer_data *device_profile_data = GetLayerDataPtr(get_dispatch_key(*pInstance), layer_data_map); 122 device_profile_data->instance = *pInstance; 123 device_profile_data->instance_dispatch_table = new VkLayerInstanceDispatchTable; 124 layer_init_instance_dispatch_table(*pInstance, device_profile_data->instance_dispatch_table, fp_get_instance_proc_addr); 125 126 uint32_t physical_device_count = 0; 127 device_profile_data->instance_dispatch_table->EnumeratePhysicalDevices(*pInstance, &physical_device_count, NULL); 128 129 VkPhysicalDevice *physical_devices = (VkPhysicalDevice *)malloc(sizeof(physical_devices[0]) * physical_device_count); 130 result = device_profile_data->instance_dispatch_table->EnumeratePhysicalDevices(*pInstance, &physical_device_count, physical_devices); 131 132 for (uint8_t i = 0; i < physical_device_count; i++) { 133 auto device_profile_api_data_it = device_profile_api_dev_data_map.find(physical_devices[i]); 134 if (device_profile_api_data_it == device_profile_api_dev_data_map.end()) { 135 device_profile_data->instance_dispatch_table 136 ->GetPhysicalDeviceProperties(physical_devices[i], &device_profile_api_dev_data_map[physical_devices[i]].phy_device_props); 137 device_profile_api_dev_data_map[physical_devices[i]].instance = *pInstance; 138 } 139 } 140 return result; 141} 142 143VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, 144 VkPhysicalDeviceProperties *pProperties) { 145 { 146 std::lock_guard<std::mutex> lock(global_lock); 147 148 // Search if we got the device limits for this device and stored in device_profile_api layer 149 auto device_profile_api_data_it = device_profile_api_dev_data_map.find(physicalDevice); 150 if (device_profile_api_data_it != device_profile_api_dev_data_map.end()) { 151 memcpy(pProperties, &device_profile_api_dev_data_map[physicalDevice].phy_device_props, sizeof(VkPhysicalDeviceProperties)); 152 } 153 } 154} 155 156VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, 157 VkFormatProperties *pProperties) { 158 { 159 std::lock_guard<std::mutex> lock(global_lock); 160 161 // Search if we got the device limits for this device and stored in device_profile_api layer 162 auto device_profile_api_data_it = device_profile_api_dev_data_map.find(physicalDevice); 163 if (device_profile_api_data_it != device_profile_api_dev_data_map.end()) { 164 auto device_format_map_it = device_profile_api_dev_data_map[physicalDevice].format_properties_map.find(format); 165 if (device_format_map_it != device_profile_api_dev_data_map[physicalDevice].format_properties_map.end()) { 166 memcpy(pProperties, &device_profile_api_dev_data_map[physicalDevice].format_properties_map[format], 167 sizeof(VkFormatProperties)); 168 } else { 169 layer_data *device_profile_data = 170 GetLayerDataPtr(get_dispatch_key(device_profile_api_dev_data_map[physicalDevice].instance), layer_data_map); 171 device_profile_data->instance_dispatch_table->GetPhysicalDeviceFormatProperties(physicalDevice, format, 172 pProperties); 173 } 174 } 175 } 176} 177 178static const VkLayerProperties device_profile_api_LayerProps = { 179 "VK_LAYER_LUNARG_device_profile_api", VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION), // specVersion 180 1, // implementationVersion 181 "LunarG device profile api Layer", 182}; 183 184template <typename T> 185VkResult EnumerateProperties(uint32_t src_count, const T *src_props, uint32_t *dst_count, T *dst_props) { 186 if (!dst_props || !src_props) { 187 *dst_count = src_count; 188 return VK_SUCCESS; 189 } 190 191 uint32_t copy_count = (*dst_count < src_count) ? *dst_count : src_count; 192 memcpy(dst_props, src_props, sizeof(T) * copy_count); 193 *dst_count = copy_count; 194 195 return (copy_count == src_count) ? VK_SUCCESS : VK_INCOMPLETE; 196} 197 198VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) { 199 return EnumerateProperties(1, &device_profile_api_LayerProps, pCount, pProperties); 200} 201 202VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, 203 VkExtensionProperties *pProperties) { 204 if (pLayerName && !strcmp(pLayerName, device_profile_api_LayerProps.layerName)) 205 return EnumerateProperties<VkExtensionProperties>(0, NULL, pCount, pProperties); 206 207 return VK_ERROR_LAYER_NOT_PRESENT; 208} 209 210VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *name) { 211 212 if (!strcmp(name, "vkSetPhysicalDeviceLimitsEXT")) return (PFN_vkVoidFunction)SetPhysicalDeviceLimitsEXT; 213 if (!strcmp(name, "vkGetOriginalPhysicalDeviceLimitsEXT")) return (PFN_vkVoidFunction)GetOriginalPhysicalDeviceLimitsEXT; 214 if (!strcmp(name, "vkSetPhysicalDeviceFormatPropertiesEXT")) return (PFN_vkVoidFunction)SetPhysicalDeviceFormatPropertiesEXT; 215 if (!strcmp(name, "vkGetOriginalPhysicalDeviceFormatPropertiesEXT")) 216 return (PFN_vkVoidFunction)GetOriginalPhysicalDeviceFormatPropertiesEXT; 217 if (instance_dispatch_table(instance)->GetPhysicalDeviceProcAddr == NULL) return NULL; 218 return instance_dispatch_table(instance)->GetPhysicalDeviceProcAddr(instance, name); 219 220} 221 222VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *name) { 223 224 if (!strcmp(name, "vkCreateInstance")) return (PFN_vkVoidFunction)CreateInstance; 225 if (!strcmp(name, "vkGetPhysicalDeviceProperties")) return (PFN_vkVoidFunction)GetPhysicalDeviceProperties; 226 if (!strcmp(name, "vkGetPhysicalDeviceFormatProperties")) return (PFN_vkVoidFunction)GetPhysicalDeviceFormatProperties; 227 if (!strcmp(name, "vkGetInstanceProcAddr")) return (PFN_vkVoidFunction)GetInstanceProcAddr; 228 if (!strcmp(name, "vkEnumerateInstanceExtensionProperties")) return (PFN_vkVoidFunction)EnumerateInstanceExtensionProperties; 229 if (!strcmp(name, "vkEnumerateInstanceLayerProperties")) return (PFN_vkVoidFunction)EnumerateInstanceLayerProperties; 230 if (!strcmp(name, "vkSetPhysicalDeviceLimitsEXT")) return (PFN_vkVoidFunction)SetPhysicalDeviceLimitsEXT; 231 if (!strcmp(name, "vkGetOriginalPhysicalDeviceLimitsEXT")) return (PFN_vkVoidFunction)GetOriginalPhysicalDeviceLimitsEXT; 232 if (!strcmp(name, "vkSetPhysicalDeviceFormatPropertiesEXT")) return (PFN_vkVoidFunction)SetPhysicalDeviceFormatPropertiesEXT; 233 if (!strcmp(name, "vkGetOriginalPhysicalDeviceFormatPropertiesEXT")) 234 return (PFN_vkVoidFunction)GetOriginalPhysicalDeviceFormatPropertiesEXT; 235 236 assert(instance); 237 238 if (instance_dispatch_table(instance)->GetInstanceProcAddr == NULL) return NULL; 239 return instance_dispatch_table(instance)->GetInstanceProcAddr(instance, name); 240} 241 242} // namespace device_profile_api 243 244VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount, 245 VkLayerProperties *pProperties) { 246 return device_profile_api::EnumerateInstanceLayerProperties(pCount, pProperties); 247} 248 249VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, 250 VkExtensionProperties *pProperties) { 251 return device_profile_api::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties); 252} 253 254VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) { 255 return device_profile_api::GetInstanceProcAddr(instance, funcName); 256} 257 258VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, 259 const char *funcName) { 260 return device_profile_api::GetPhysicalDeviceProcAddr(instance, funcName); 261} 262 263VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) { 264 assert(pVersionStruct != NULL); 265 assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT); 266 267 // Fill in the function pointers if our version is at least capable of having the structure contain them. 268 if (pVersionStruct->loaderLayerInterfaceVersion >= 2) { 269 pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr; 270 pVersionStruct->pfnGetDeviceProcAddr = nullptr; 271 pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr; 272 } 273 274 if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) { 275 device_profile_api::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion; 276 } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) { 277 pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION; 278 } 279 280 return VK_SUCCESS; 281} 282