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