1/*
2 * Copyright (c) 2021 The Khronos Group Inc.
3 * Copyright (c) 2021 Valve Corporation
4 * Copyright (c) 2021 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and/or associated documentation files (the "Materials"), to
8 * deal in the Materials without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Materials, and to permit persons to whom the Materials are
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice(s) and this permission notice shall be included in
14 * all copies or substantial portions of the Materials.
15 *
16 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 *
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23 * USE OR OTHER DEALINGS IN THE MATERIALS.
24 *
25 * Author: Charles Giessen <charles@lunarg.com>
26 */
27
28#include "test_environment.h"
29#include <functional>
30#include <tuple>
31
32enum class TestConfig {
33    add_layer_implementation,
34    add_layer_interception,
35};
36
37bool has_flag(std::vector<TestConfig> const& flags, TestConfig config) {
38    for (auto const& flag : flags)
39        if (flag == config) return true;
40    return false;
41}
42
43/*
44 Creates a TestICD with a function unknown to the loader called vkNotRealFuncTEST. The TestICD, when
45 vk_icdGetPhysicalDeviceProcAddr is called, will return the custom_physical_device_function if the function name matches
46 vkNotRealFuncTEST. The test then calls the function to verify that the unknown physical device function dispatching is
47 working correctly.
48*/
49template <typename DispatchableHandleType>
50struct custom_functions {
51    static VKAPI_ATTR uint32_t VKAPI_CALL func_zero(DispatchableHandleType, uint32_t foo) { return foo; };
52    static VKAPI_ATTR uint32_t VKAPI_CALL func_one(DispatchableHandleType, uint32_t foo, uint32_t bar) { return foo + bar; };
53    static VKAPI_ATTR float VKAPI_CALL func_two(DispatchableHandleType, uint32_t foo, uint32_t bar, float baz) {
54        return baz + foo + bar;
55    };
56    static VKAPI_ATTR int VKAPI_CALL func_three(DispatchableHandleType, int* ptr_a, int* ptr_b) { return *ptr_a + *ptr_b; };
57    static VKAPI_ATTR float VKAPI_CALL func_four(DispatchableHandleType, int* ptr_a, int* ptr_b, int foo, int bar, float k, float l,
58                                                 char a, char b, char c) {
59        return *ptr_a + *ptr_b + foo + bar + k + l + static_cast<int>(a) + static_cast<int>(b) + static_cast<int>(c);
60    };
61};
62
63/*
64Functions for testing of layer interception of unknown functions. Note the need to pass a pointer to the layer and the name
65of the called function as a parameter, this is necessary to allow a generic layer implementation, as the layer must look up
66the function pointer to use. A real layer would store the function pointer in a dedicated structure per-instance/device, but
67since the TestLayer is a generic layer, there isn't a fixed list of functions that should be supported.
68*/
69
70PFN_vkVoidFunction find_custom_func(TestLayer* layer, const char* name) {
71    if (layer->custom_dispatch_functions.count(name) > 0) {
72        return layer->custom_dispatch_functions.at(name);
73    }
74    return nullptr;
75}
76
77template <typename DispatchableHandleType>
78struct layer_intercept_functions {
79    static VKAPI_ATTR uint32_t VKAPI_CALL func_zero(DispatchableHandleType handle, TestLayer* layer, const char* name, uint32_t i) {
80        auto func = reinterpret_cast<decltype(&func_zero)>(find_custom_func(layer, name));
81        if (func == nullptr) return 1337;
82        return func(handle, layer, name, i + 3);
83    }
84    static VKAPI_ATTR uint32_t VKAPI_CALL func_one(DispatchableHandleType handle, TestLayer* layer, const char* name, uint32_t i,
85                                                   float f) {
86        auto func = reinterpret_cast<decltype(&func_one)>(find_custom_func(layer, name));
87        if (func == nullptr) return 1337;
88        return func(handle, layer, name, i + 2, f + 1.f);
89    }
90    static VKAPI_ATTR float VKAPI_CALL func_two(DispatchableHandleType handle, TestLayer* layer, const char* name, uint32_t foo,
91                                                uint32_t bar, float baz) {
92        auto func = reinterpret_cast<decltype(&func_two)>(find_custom_func(layer, name));
93        if (func == nullptr) return -1337;
94        return func(handle, layer, name, foo + 1, bar + 2, baz * 2);
95    };
96    static VKAPI_ATTR int VKAPI_CALL func_three(DispatchableHandleType handle, TestLayer* layer, const char* name, int* ptr_a,
97                                                int* ptr_b) {
98        auto func = reinterpret_cast<decltype(&func_three)>(find_custom_func(layer, name));
99        if (func == nullptr) return -1337;
100        *ptr_a += 1;
101        *ptr_b -= 2;
102        return func(handle, layer, name, ptr_a, ptr_b);
103    };
104    static VKAPI_ATTR float VKAPI_CALL func_four(DispatchableHandleType handle, TestLayer* layer, const char* name, int* ptr_a,
105                                                 int* ptr_b, int foo, int bar, float k, float l, char, char, char) {
106        auto func = reinterpret_cast<decltype(&func_four)>(find_custom_func(layer, name));
107        if (func == nullptr) return -1337.f;
108        return func(handle, layer, name, ptr_a, ptr_b, foo + 4, bar + 5, k + 1, l + 2, 'd', 'e', 'f');
109    };
110};
111
112template <typename DispatchableHandleType>
113struct layer_implementation_functions {
114    static VKAPI_ATTR uint32_t VKAPI_CALL func_zero(DispatchableHandleType, TestLayer*, const char*, uint32_t i) { return i * 3; }
115    static VKAPI_ATTR uint32_t VKAPI_CALL func_one(DispatchableHandleType, TestLayer*, const char*, uint32_t i, float f) {
116        return static_cast<int>(i * 3 + f * 10.f);
117    }
118    static VKAPI_ATTR float VKAPI_CALL func_two(DispatchableHandleType, TestLayer*, const char*, uint32_t foo, uint32_t bar,
119                                                float baz) {
120        return baz + foo + bar;
121    };
122    static VKAPI_ATTR int VKAPI_CALL func_three(DispatchableHandleType, TestLayer*, const char*, int* ptr_a, int* ptr_b) {
123        return *ptr_a + *ptr_b;
124    };
125    static VKAPI_ATTR float VKAPI_CALL func_four(DispatchableHandleType, TestLayer*, const char*, int* ptr_a, int* ptr_b, int foo,
126                                                 int bar, float k, float l, char a, char b, char c) {
127        return *ptr_a + *ptr_b + foo + bar + k + l + static_cast<int>(a) + static_cast<int>(b) + static_cast<int>(c);
128    };
129};
130
131// Add function_count strings to the func_names vector, starting at function_start place. Essentially a utility for filling
132// up a list of names to use later
133void add_function_names(std::vector<std::string>& func_names, uint32_t function_count, uint32_t function_start = 0) {
134    for (uint32_t i = function_start; i < function_start + function_count;) {
135        func_names.push_back(std::string("vkNotIntRealFuncTEST_") + std::to_string(i++));
136        func_names.push_back(std::string("vkNotIntRealIntFuncTEST_") + std::to_string(i++));
137        func_names.push_back(std::string("vkIntNotIntRealFloatFuncTEST_") + std::to_string(i++));
138        func_names.push_back(std::string("vkNotRealFuncPointerPointerTEST_") + std::to_string(i++));
139        func_names.push_back(std::string("vkNotRealFuncTEST_pointer_pointer_int_int_float_float_char_char_char_") +
140                             std::to_string(i++));
141    }
142}
143
144// Add data to the function_list, which could be a driver or a layer list of implementation functions.
145template <typename FunctionStruct>
146void fill_implementation_functions(std::vector<VulkanFunction>& function_list, std::vector<std::string>& func_names,
147                                   FunctionStruct const& funcs, uint32_t function_count, uint32_t function_start = 0) {
148    for (uint32_t i = function_start; i < function_start + function_count;) {
149        function_list.push_back(VulkanFunction{func_names.at(i++), to_vkVoidFunction(funcs.func_zero)});
150        function_list.push_back(VulkanFunction{func_names.at(i++), to_vkVoidFunction(funcs.func_one)});
151        function_list.push_back(VulkanFunction{func_names.at(i++), to_vkVoidFunction(funcs.func_two)});
152        function_list.push_back(VulkanFunction{func_names.at(i++), to_vkVoidFunction(funcs.func_three)});
153        function_list.push_back(VulkanFunction{func_names.at(i++), to_vkVoidFunction(funcs.func_four)});
154    }
155}
156
157// Add device interception functions to a layer. Need to call `add_custom_device_interception_function` since the layer has
158// to setup a unordered_map for storing the next function in the chain, and key it based on the name
159template <typename FunctionStruct>
160void fill_device_intercept_functions(TestLayer& layer, std::vector<std::string>& func_names, FunctionStruct const& funcs,
161                                     uint32_t function_count, uint32_t function_start = 0) {
162    for (uint32_t i = function_start; i < function_start + function_count;) {
163        layer.add_custom_device_interception_function(func_names.at(i++), to_vkVoidFunction(funcs.func_zero));
164        layer.add_custom_device_interception_function(func_names.at(i++), to_vkVoidFunction(funcs.func_one));
165        layer.add_custom_device_interception_function(func_names.at(i++), to_vkVoidFunction(funcs.func_two));
166        layer.add_custom_device_interception_function(func_names.at(i++), to_vkVoidFunction(funcs.func_three));
167        layer.add_custom_device_interception_function(func_names.at(i++), to_vkVoidFunction(funcs.func_four));
168    }
169}
170// Add physical device interception functions to a layer. Need to call `add_custom_device_interception_function` since the
171// layer has to setup a unordered_map for storing the next function in the chain, and key it based on the name
172template <typename FunctionStruct>
173void fill_phys_dev_intercept_functions(TestLayer& layer, std::vector<std::string>& func_names, FunctionStruct const& funcs,
174                                       uint32_t function_count, uint32_t function_start = 0) {
175    for (uint32_t i = function_start; i < function_start + function_count;) {
176        layer.add_custom_physical_device_intercept_function(func_names.at(i++), to_vkVoidFunction(funcs.func_zero));
177        layer.add_custom_physical_device_intercept_function(func_names.at(i++), to_vkVoidFunction(funcs.func_one));
178        layer.add_custom_physical_device_intercept_function(func_names.at(i++), to_vkVoidFunction(funcs.func_two));
179        layer.add_custom_physical_device_intercept_function(func_names.at(i++), to_vkVoidFunction(funcs.func_three));
180        layer.add_custom_physical_device_intercept_function(func_names.at(i++), to_vkVoidFunction(funcs.func_four));
181    }
182}
183
184template <typename FunctionLoader, typename ParentType, typename DispatchableHandleType, typename FunctionStruct>
185void check_custom_functions(FunctionLoader& loader, ParentType parent, DispatchableHandleType handle, FunctionStruct const&,
186                            std::vector<std::string>& func_names, uint32_t function_count, uint32_t function_start = 0) {
187    for (uint32_t i = function_start; i < function_start + function_count;) {
188        decltype(FunctionStruct::func_zero)* returned_func_i = loader.load(parent, func_names.at(i++).c_str());
189        ASSERT_NE(returned_func_i, nullptr);
190        EXPECT_EQ(returned_func_i(handle, i * 10), i * 10);
191
192        decltype(FunctionStruct::func_one)* returned_func_ii = loader.load(parent, func_names.at(i++).c_str());
193        ASSERT_NE(returned_func_ii, nullptr);
194        EXPECT_EQ(returned_func_ii(handle, i * 10, i * 5), i * 10 + i * 5);
195
196        decltype(FunctionStruct::func_two)* returned_func_iif = loader.load(parent, func_names.at(i++).c_str());
197        ASSERT_NE(returned_func_iif, nullptr);
198        EXPECT_NEAR(returned_func_iif(handle, i * 10, i * 5, 0.1234f), i * 10 + i * 5 + 0.1234f, 0.001);
199
200        int x = 5;
201        int y = -505;
202        decltype(FunctionStruct::func_three)* returned_func_pp = loader.load(parent, func_names.at(i++).c_str());
203        ASSERT_NE(returned_func_pp, nullptr);
204        EXPECT_EQ(returned_func_pp(handle, &x, &y), -500);
205
206        x = 5;
207        y = -505;
208        decltype(FunctionStruct::func_four)* returned_func_ppiiffccc = loader.load(parent, func_names.at(i++).c_str());
209        ASSERT_NE(returned_func_ppiiffccc, nullptr);
210        EXPECT_NEAR(returned_func_ppiiffccc(handle, &x, &y, 200, 300, 0.123f, 1001.89f, 'a', 'b', 'c'),
211                    -500 + 200 + 300 + 0.123 + 1001.89 + 97 + 98 + 99, 0.001f);
212    }
213}
214
215template <typename FunctionLoader, typename ParentType, typename DispatchableHandleType, typename FunctionStruct>
216void check_layer_custom_functions(FunctionLoader& loader, ParentType parent, DispatchableHandleType handle, TestLayer& layer,
217                                  FunctionStruct const&, std::vector<std::string>& func_names, uint32_t function_count,
218                                  uint32_t function_start = 0) {
219    for (uint32_t i = function_start; i < function_start + function_count;) {
220        decltype(FunctionStruct::func_zero)* returned_func_i = loader.load(parent, func_names.at(i).c_str());
221        ASSERT_NE(returned_func_i, nullptr);
222        EXPECT_EQ(returned_func_i(handle, &layer, func_names.at(i).c_str(), i), (i + 3) * 3);
223        i++;
224        decltype(FunctionStruct::func_one)* returned_func_if = loader.load(parent, func_names.at(i).c_str());
225        ASSERT_NE(returned_func_if, nullptr);
226        EXPECT_EQ(returned_func_if(handle, &layer, func_names.at(i).c_str(), i, i + 1.f), (i + 2) * 3 + (i + 2) * 10);
227        i++;
228
229        decltype(FunctionStruct::func_two)* returned_func_iif = loader.load(parent, func_names.at(i).c_str());
230        ASSERT_NE(returned_func_iif, nullptr);
231        EXPECT_NEAR(returned_func_iif(handle, &layer, func_names.at(i).c_str(), i * 10, i * 5, 0.1234f),
232                    (i * 10 + 1) + (i * 5 + 2) + (0.1234f * 2.f), 0.001);
233        i++;
234
235        int x = 5 + i;
236        int y = -505 - i;
237        decltype(FunctionStruct::func_three)* returned_func_pp = loader.load(parent, func_names.at(i).c_str());
238        ASSERT_NE(returned_func_pp, nullptr);
239        EXPECT_EQ(returned_func_pp(handle, &layer, func_names.at(i).c_str(), &x, &y),
240                  (5 + static_cast<int>(i) + 1) + (-505 - static_cast<int>(i) - 2));
241        i++;
242
243        x = 5;
244        y = -505;
245        decltype(FunctionStruct::func_four)* returned_func_ppiiffccc = loader.load(parent, func_names.at(i).c_str());
246        ASSERT_NE(returned_func_ppiiffccc, nullptr);
247        EXPECT_NEAR(
248            returned_func_ppiiffccc(handle, &layer, func_names.at(i).c_str(), &x, &y, 200, 300, 0.123f, 1001.89f, 'a', 'b', 'c'),
249            -500 + (200 + 4) + (300 + 5) + (0.123 + 1) + (1001.89 + 2) + 100 + 101 + 102,
250            0.001f);  // layer changes abc to def
251        i++;
252    }
253}
254
255template <typename FunctionLoader, typename ParentType, typename DispatchableHandleType, typename FunctionStruct>
256void check_layer_custom_functions_no_implementation(FunctionLoader& loader, ParentType parent, DispatchableHandleType handle,
257                                                    TestLayer& layer, FunctionStruct const&, std::vector<std::string>& func_names,
258                                                    uint32_t function_count, uint32_t function_start = 0) {
259    for (uint32_t i = function_start; i < function_start + function_count;) {
260        decltype(FunctionStruct::func_zero)* returned_func_i = loader.load(parent, func_names.at(i).c_str());
261        ASSERT_NE(returned_func_i, nullptr);
262        EXPECT_EQ(1337U, returned_func_i(handle, &layer, func_names.at(i).c_str(), i));
263        i++;
264        decltype(FunctionStruct::func_one)* returned_func_if = loader.load(parent, func_names.at(i).c_str());
265        ASSERT_NE(returned_func_if, nullptr);
266        EXPECT_EQ(1337U, returned_func_if(handle, &layer, func_names.at(i).c_str(), i, i + 1.f));
267        i++;
268
269        decltype(FunctionStruct::func_two)* returned_func_iif = loader.load(parent, func_names.at(i).c_str());
270        ASSERT_NE(returned_func_iif, nullptr);
271        EXPECT_NEAR(-1337.0, returned_func_iif(handle, &layer, func_names.at(i).c_str(), i * 10, i * 5, 0.1234f), 0.001);
272        i++;
273
274        int x = 5 + i;
275        int y = -505 - i;
276        decltype(FunctionStruct::func_three)* returned_func_pp = loader.load(parent, func_names.at(i).c_str());
277        ASSERT_NE(returned_func_pp, nullptr);
278        EXPECT_EQ(-1337, returned_func_pp(handle, &layer, func_names.at(i).c_str(), &x, &y));
279        i++;
280
281        x = 5;
282        y = -505;
283        decltype(FunctionStruct::func_four)* returned_func_ppiiffccc = loader.load(parent, func_names.at(i).c_str());
284        ASSERT_NE(returned_func_ppiiffccc, nullptr);
285        EXPECT_NEAR(
286            -1337.0,
287            returned_func_ppiiffccc(handle, &layer, func_names.at(i).c_str(), &x, &y, 200, 300, 0.123f, 1001.89f, 'a', 'b', 'c'),
288            0.001);
289        i++;
290    }
291}
292
293template <typename FunctionLoader, typename ParentType, typename DispatchableHandleType, typename FunctionStruct>
294void check_layer_custom_functions_no_interception(FunctionLoader& loader, ParentType parent, DispatchableHandleType handle,
295                                                  TestLayer& layer, FunctionStruct const&, std::vector<std::string>& func_names,
296                                                  uint32_t function_count, uint32_t function_start = 0) {
297    for (uint32_t i = function_start; i < function_start + function_count;) {
298        decltype(FunctionStruct::func_zero)* returned_func_i = loader.load(parent, func_names.at(i).c_str());
299        ASSERT_NE(returned_func_i, nullptr);
300        EXPECT_EQ(returned_func_i(handle, &layer, func_names.at(i).c_str(), i), (i)*3);
301        i++;
302        decltype(FunctionStruct::func_one)* returned_func_if = loader.load(parent, func_names.at(i).c_str());
303        ASSERT_NE(returned_func_if, nullptr);
304        EXPECT_EQ(returned_func_if(handle, &layer, func_names.at(i).c_str(), i, i + 1.f), (i)*3 + (i + 1) * 10);
305        i++;
306
307        decltype(FunctionStruct::func_two)* returned_func_iif = loader.load(parent, func_names.at(i).c_str());
308        ASSERT_NE(returned_func_iif, nullptr);
309        EXPECT_NEAR(returned_func_iif(handle, &layer, func_names.at(i).c_str(), i * 10, i * 5, 0.1234f),
310                    (i * 10) + (i * 5) + (0.1234f), 0.001);
311        i++;
312
313        int x = 5 + i;
314        int y = -505 - i;
315        decltype(FunctionStruct::func_three)* returned_func_pp = loader.load(parent, func_names.at(i).c_str());
316        ASSERT_NE(returned_func_pp, nullptr);
317        EXPECT_EQ(returned_func_pp(handle, &layer, func_names.at(i).c_str(), &x, &y),
318                  (5 + static_cast<int>(i)) + (-505 - static_cast<int>(i)));
319        i++;
320
321        x = 5;
322        y = -505;
323        decltype(FunctionStruct::func_four)* returned_func_ppiiffccc = loader.load(parent, func_names.at(i).c_str());
324        ASSERT_NE(returned_func_ppiiffccc, nullptr);
325        EXPECT_NEAR(
326            returned_func_ppiiffccc(handle, &layer, func_names.at(i).c_str(), &x, &y, 200, 300, 0.123f, 1001.89f, 'a', 'b', 'c'),
327            -500 + (200) + (300) + (0.123) + (1001.89) + 97 + 98 + 99, 0.001f);
328        i++;
329    }
330}
331
332using custom_physical_device_functions = custom_functions<VkPhysicalDevice>;
333using layer_intercept_physical_device_functions = layer_intercept_functions<VkPhysicalDevice>;
334using layer_implementation_physical_device_functions = layer_implementation_functions<VkPhysicalDevice>;
335
336TEST(UnknownFunction, PhysicalDeviceFunction) {
337    FrameworkEnvironment env{};
338    auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
339    uint32_t function_count = MAX_NUM_UNKNOWN_EXTS;
340    std::vector<std::string> function_names;
341    add_function_names(function_names, function_count);
342
343    fill_implementation_functions(driver.physical_devices.at(0).custom_physical_device_functions, function_names,
344                                  custom_physical_device_functions{}, function_count);
345    InstWrapper inst{env.vulkan_functions};
346    inst.CheckCreate();
347
348    VkPhysicalDevice phys_dev = inst.GetPhysDev();
349    check_custom_functions(env.vulkan_functions, inst.inst, phys_dev, custom_physical_device_functions{}, function_names,
350                           function_count);
351}
352
353TEST(UnknownFunction, PhysicalDeviceFunctionMultipleDriverSupport) {
354    FrameworkEnvironment env{};
355    auto& driver_0 = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
356    auto& driver_1 = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
357    uint32_t function_count = MAX_NUM_UNKNOWN_EXTS;
358    std::vector<std::string> function_names;
359    add_function_names(function_names, function_count);
360
361    // used to identify the GPUs
362    driver_0.physical_devices.emplace_back("physical_device_0").properties.deviceType = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
363    driver_1.physical_devices.emplace_back("physical_device_1").properties.deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
364
365    for (uint32_t i = 0; i < function_count / 10; i++) {
366        fill_implementation_functions(driver_0.physical_devices.at(0).custom_physical_device_functions, function_names,
367                                      custom_physical_device_functions{}, 5, i * 10);
368        fill_implementation_functions(driver_1.physical_devices.at(0).custom_physical_device_functions, function_names,
369                                      custom_physical_device_functions{}, 5, i * 10 + 5);
370    }
371    InstWrapper inst{env.vulkan_functions};
372    inst.CheckCreate();
373
374    auto phys_devs = inst.GetPhysDevs(2);
375    VkPhysicalDevice phys_dev_0 = phys_devs[0];
376    VkPhysicalDevice phys_dev_1 = phys_devs[1];
377    VkPhysicalDeviceProperties props{};
378    env.vulkan_functions.vkGetPhysicalDeviceProperties(phys_devs[0], &props);
379    if (props.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
380        phys_dev_0 = phys_devs[1];
381        phys_dev_1 = phys_devs[0];
382    }
383    for (uint32_t i = 0; i < function_count / 10; i++) {
384        check_custom_functions(env.vulkan_functions, inst.inst, phys_dev_0, custom_physical_device_functions{}, function_names, 5,
385                               i * 10);
386        check_custom_functions(env.vulkan_functions, inst.inst, phys_dev_1, custom_physical_device_functions{}, function_names, 5,
387                               i * 10 + 5);
388    }
389}
390
391// Add unknown functions to driver 0, and try to use them on driver 1.
392TEST(UnknownFunctionDeathTests, PhysicalDeviceFunctionErrorPath) {
393    FrameworkEnvironment env{};
394    auto& driver_0 = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
395    auto& driver_1 = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
396    std::vector<std::string> function_names;
397    add_function_names(function_names, 1);
398
399    // used to identify the GPUs
400    driver_0.physical_devices.emplace_back("physical_device_0").properties.deviceType = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
401    driver_1.physical_devices.emplace_back("physical_device_1").properties.deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
402    function_names.push_back(std::string("vkNotIntRealFuncTEST_0"));
403
404    custom_physical_device_functions funcs{};
405    driver_0.physical_devices.at(0).custom_physical_device_functions.push_back(
406        VulkanFunction{function_names.back(), to_vkVoidFunction(funcs.func_zero)});
407
408    InstWrapper inst{env.vulkan_functions};
409    inst.CheckCreate();
410
411    auto phys_devs = inst.GetPhysDevs(2);
412    VkPhysicalDevice phys_dev_to_use = phys_devs[1];
413    VkPhysicalDeviceProperties props{};
414    env.vulkan_functions.vkGetPhysicalDeviceProperties(phys_devs[1], &props);
415    if (props.deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) phys_dev_to_use = phys_devs[0];
416    // use the wrong GPU to query the functions, should get 5 errors
417
418    decltype(custom_physical_device_functions::func_zero)* returned_func_i =
419        env.vulkan_functions.load(inst.inst, function_names.at(0).c_str());
420    ASSERT_NE(returned_func_i, nullptr);
421    ASSERT_DEATH(returned_func_i(phys_dev_to_use, 0), "Function vkNotIntRealFuncTEST_0 not supported for this physical device");
422}
423
424TEST(UnknownFunction, PhysicalDeviceFunctionWithImplicitLayerImplementation) {
425    FrameworkEnvironment env{};
426    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
427    uint32_t function_count = MAX_NUM_UNKNOWN_EXTS;
428    std::vector<std::string> function_names;
429    add_function_names(function_names, function_count);
430
431    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
432                                                         .set_name("VK_LAYER_implicit_layer_unknown_function_intercept")
433                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
434                                                         .set_disable_environment("DISABLE_ME")),
435                           "implicit_layer_unknown_function_intercept.json");
436    auto& layer = env.get_test_layer();
437    fill_implementation_functions(layer.custom_physical_device_implementation_functions, function_names,
438                                  layer_implementation_physical_device_functions{}, function_count);
439
440    InstWrapper inst{env.vulkan_functions};
441    inst.CheckCreate();
442
443    VkPhysicalDevice phys_dev = inst.GetPhysDev();
444    check_layer_custom_functions_no_interception(env.vulkan_functions, inst.inst, phys_dev, layer,
445                                                 layer_implementation_physical_device_functions{}, function_names, function_count);
446}
447
448TEST(UnknownFunction, PhysicalDeviceFunctionMultipleDriverSupportWithImplicitLayerImplementation) {
449    FrameworkEnvironment env{};
450    auto& driver_0 = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
451    auto& driver_1 = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
452    uint32_t function_count = MAX_NUM_UNKNOWN_EXTS;
453    std::vector<std::string> function_names;
454    add_function_names(function_names, function_count);
455
456    // used to identify the GPUs
457    driver_0.physical_devices.emplace_back("physical_device_0").properties.deviceType = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
458    driver_1.physical_devices.emplace_back("physical_device_1").properties.deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
459    for (uint32_t i = 0; i < function_count / 10; i++) {
460        fill_implementation_functions(driver_0.physical_devices.at(0).custom_physical_device_functions, function_names,
461                                      custom_physical_device_functions{}, 5, i * 10);
462        fill_implementation_functions(driver_1.physical_devices.at(0).custom_physical_device_functions, function_names,
463                                      custom_physical_device_functions{}, 5, i * 10 + 5);
464    }
465
466    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
467                                                         .set_name("VK_LAYER_implicit_layer_unknown_function_intercept")
468                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
469                                                         .set_disable_environment("DISABLE_ME")),
470                           "implicit_layer_unknown_function_intercept.json");
471
472    InstWrapper inst{env.vulkan_functions};
473    inst.CheckCreate();
474
475    auto phys_devs = inst.GetPhysDevs(2);
476    VkPhysicalDevice phys_dev_0 = phys_devs[0];
477    VkPhysicalDevice phys_dev_1 = phys_devs[1];
478    VkPhysicalDeviceProperties props{};
479    env.vulkan_functions.vkGetPhysicalDeviceProperties(phys_devs[0], &props);
480    if (props.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
481        phys_dev_0 = phys_devs[1];
482        phys_dev_1 = phys_devs[0];
483    }
484    for (uint32_t i = 0; i < function_count / 10; i++) {
485        check_custom_functions(env.vulkan_functions, inst.inst, phys_dev_0, custom_physical_device_functions{}, function_names, 5,
486                               i * 10);
487        check_custom_functions(env.vulkan_functions, inst.inst, phys_dev_1, custom_physical_device_functions{}, function_names, 5,
488                               i * 10 + 5);
489    }
490}
491
492TEST(UnknownFunction, PhysicalDeviceFunctionWithImplicitLayerInterception) {
493    FrameworkEnvironment env{};
494    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
495    uint32_t function_count = MAX_NUM_UNKNOWN_EXTS;
496
497    std::vector<std::string> function_names;
498    add_function_names(function_names, function_count);
499
500    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
501                                                         .set_name("VK_LAYER_implicit_layer_unknown_function_intercept")
502                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
503                                                         .set_disable_environment("DISABLE_ME")),
504                           "implicit_layer_unknown_function_intercept.json");
505    auto& layer = env.get_test_layer();
506    fill_phys_dev_intercept_functions(layer, function_names, layer_intercept_physical_device_functions{}, function_count);
507
508    InstWrapper inst{env.vulkan_functions};
509    inst.CheckCreate();
510
511    VkPhysicalDevice phys_dev = inst.GetPhysDev();
512    check_layer_custom_functions_no_implementation(env.vulkan_functions, inst.inst, phys_dev, layer,
513                                                   layer_intercept_physical_device_functions{}, function_names, function_count);
514}
515
516TEST(UnknownFunction, PhysicalDeviceFunctionDriverSupportWithImplicitLayerInterception) {
517    FrameworkEnvironment env{};
518    auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
519    uint32_t function_count = 100;
520    std::vector<std::string> function_names;
521    add_function_names(function_names, function_count);
522    fill_implementation_functions(driver.physical_devices.at(0).custom_physical_device_functions, function_names,
523                                  layer_implementation_physical_device_functions{}, function_count);
524    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
525                                                         .set_name("VK_LAYER_implicit_layer_unknown_function_intercept")
526                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
527                                                         .set_disable_environment("DISABLE_ME")),
528                           "implicit_layer_unknown_function_intercept.json");
529    auto& layer = env.get_test_layer();
530    fill_phys_dev_intercept_functions(layer, function_names, layer_intercept_physical_device_functions{}, function_count);
531
532    InstWrapper inst{env.vulkan_functions};
533    inst.CheckCreate();
534
535    VkPhysicalDevice phys_dev = inst.GetPhysDev();
536    check_layer_custom_functions(env.vulkan_functions, inst.inst, phys_dev, layer, layer_intercept_physical_device_functions{},
537                                 function_names, function_count);
538}
539
540TEST(UnknownFunction, PhysicalDeviceFunctionWithMultipleImplicitLayersInterception) {
541    FrameworkEnvironment env{};
542    auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
543    std::vector<std::string> function_names;
544    uint32_t function_count = MAX_NUM_UNKNOWN_EXTS;
545    add_function_names(function_names, function_count);
546    driver.physical_devices.emplace_back("physical_device_0");
547
548    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
549                                                         .set_name("VK_LAYER_implicit_layer_unknown_function_intercept_0")
550                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
551                                                         .set_disable_environment("DISABLE_ME")),
552                           "implicit_layer_unknown_function_intercept_0.json");
553    auto& layer_0 = env.get_test_layer(0);
554    layer_0.set_use_gipa_GetPhysicalDeviceProcAddr(true);
555    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
556                                                         .set_name("VK_LAYER_implicit_layer_unknown_function_intercept_1")
557                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
558                                                         .set_disable_environment("DISABLE_ME")),
559                           "implicit_layer_unknown_function_intercept_1.json");
560    auto& layer_1 = env.get_test_layer(1);
561    layer_1.set_use_gipa_GetPhysicalDeviceProcAddr(false);
562    for (uint32_t i = 0; i < function_count / 10; i++) {
563        fill_implementation_functions(driver.physical_devices.at(0).custom_physical_device_functions, function_names,
564                                      layer_implementation_physical_device_functions{}, 5, i * 10);
565        fill_phys_dev_intercept_functions(layer_0, function_names, layer_intercept_physical_device_functions{}, 5, i * 10);
566        fill_phys_dev_intercept_functions(layer_1, function_names, layer_intercept_physical_device_functions{}, 5, i * 10 + 5);
567    }
568    InstWrapper inst{env.vulkan_functions};
569    inst.CheckCreate();
570
571    VkPhysicalDevice phys_dev = inst.GetPhysDev();
572    for (uint32_t i = 0; i < function_count / 10; i++) {
573        check_layer_custom_functions(env.vulkan_functions, inst.inst, phys_dev, layer_0,
574                                     layer_intercept_physical_device_functions{}, function_names, 5, i * 10);
575        check_layer_custom_functions_no_implementation(env.vulkan_functions, inst.inst, phys_dev, layer_1,
576                                                       layer_intercept_physical_device_functions{}, function_names, 5, i * 10 + 5);
577    }
578}
579
580template <typename ParentType>
581ParentType get_parent_type(InstWrapper const& inst, DeviceWrapper const& dev);
582
583template <>
584VkInstance get_parent_type<VkInstance>(InstWrapper const& inst, DeviceWrapper const&) {
585    return inst.inst;
586}
587template <>
588VkDevice get_parent_type<VkDevice>(InstWrapper const&, DeviceWrapper const& dev) {
589    return dev.dev;
590}
591
592template <typename DispatchableHandleType>
593DispatchableHandleType get_dispatch_handle(FrameworkEnvironment& env, DeviceWrapper const& dev,
594                                           std::vector<TestConfig> const& flags);
595
596template <>
597VkDevice get_dispatch_handle<VkDevice>(FrameworkEnvironment&, DeviceWrapper const& dev, std::vector<TestConfig> const&) {
598    return dev.dev;
599}
600
601template <>
602VkCommandBuffer get_dispatch_handle<VkCommandBuffer>(FrameworkEnvironment& env, DeviceWrapper const& dev,
603                                                     std::vector<TestConfig> const&) {
604    VkCommandPool command_pool;
605    VkCommandPoolCreateInfo pool_create_info{};
606    DeviceFunctions funcs{env.vulkan_functions, dev};
607    funcs.vkCreateCommandPool(dev, &pool_create_info, nullptr, &command_pool);
608    VkCommandBuffer command_buffer;
609    VkCommandBufferAllocateInfo alloc_info{};
610    alloc_info.commandBufferCount = 1;
611    alloc_info.commandPool = command_pool;
612    funcs.vkAllocateCommandBuffers(dev, &alloc_info, &command_buffer);
613    return command_buffer;
614}
615
616template <>
617VkQueue get_dispatch_handle<VkQueue>(FrameworkEnvironment& env, DeviceWrapper const& dev, std::vector<TestConfig> const&) {
618    DeviceFunctions funcs{env.vulkan_functions, dev.dev};
619    VkQueue queue;
620    funcs.vkGetDeviceQueue(dev, 0, 0, &queue);
621    return queue;
622}
623
624template <typename ParentType, typename DispatchableHandleType>
625void unknown_function_test_impl(std::vector<TestConfig> const& flags) {
626    using custom_functions_type = custom_functions<DispatchableHandleType>;
627    using layer_implementation_functions_type = layer_implementation_functions<DispatchableHandleType>;
628    using layer_intercept_functions_type = layer_intercept_functions<DispatchableHandleType>;
629
630    FrameworkEnvironment env{};
631    auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
632    uint32_t function_count = MAX_NUM_UNKNOWN_EXTS;
633
634    std::vector<std::string> function_names;
635    add_function_names(function_names, function_count);
636
637    if (has_flag(flags, TestConfig::add_layer_interception)) {
638        fill_implementation_functions(driver.physical_devices.back().known_device_functions, function_names,
639                                      layer_implementation_functions_type{}, function_count);
640    } else {
641        fill_implementation_functions(driver.physical_devices.back().known_device_functions, function_names,
642                                      custom_functions_type{}, function_count);
643    }
644    TestLayer* layer_ptr = nullptr;
645    if (has_flag(flags, TestConfig::add_layer_implementation) || has_flag(flags, TestConfig::add_layer_interception)) {
646        env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
647                                                             .set_name("VK_LAYER_implicit_layer_unknown_function_intercept")
648                                                             .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
649                                                             .set_disable_environment("DISABLE_ME")),
650                               "implicit_layer_unknown_function_intercept.json");
651        layer_ptr = &env.get_test_layer();
652    }
653    if (has_flag(flags, TestConfig::add_layer_implementation) && has_flag(flags, TestConfig::add_layer_interception)) {
654        for (uint32_t i = 0; i < function_count / 10; i++) {
655            fill_implementation_functions(layer_ptr->custom_device_implementation_functions, function_names,
656                                          layer_implementation_functions_type{}, 5, i * 10);
657            fill_device_intercept_functions(*layer_ptr, function_names, layer_intercept_functions_type{}, 5, i * 10 + 5);
658        }
659    } else if (has_flag(flags, TestConfig::add_layer_implementation)) {
660        fill_implementation_functions(layer_ptr->custom_device_implementation_functions, function_names, custom_functions_type{},
661                                      function_count);
662    } else if (has_flag(flags, TestConfig::add_layer_interception)) {
663        fill_device_intercept_functions(*layer_ptr, function_names, layer_intercept_functions_type{}, function_count);
664    }
665
666    InstWrapper inst{env.vulkan_functions};
667    inst.CheckCreate();
668
669    DeviceWrapper dev{inst};
670    dev.create_info.add_device_queue({});
671    dev.CheckCreate(inst.GetPhysDev());
672    auto dispatch_type = get_dispatch_handle<DispatchableHandleType>(env, dev, flags);
673    auto parent_type = get_parent_type<ParentType>(inst, dev);
674
675    if (has_flag(flags, TestConfig::add_layer_implementation) && has_flag(flags, TestConfig::add_layer_interception)) {
676        for (uint32_t i = 0; i < function_count / 10; i++) {
677            check_layer_custom_functions_no_interception(env.vulkan_functions, parent_type, dispatch_type, *layer_ptr,
678                                                         layer_implementation_functions_type{}, function_names, 5, i * 10);
679        }
680    } else if (has_flag(flags, TestConfig::add_layer_interception)) {
681        check_layer_custom_functions(env.vulkan_functions, parent_type, dispatch_type, *layer_ptr, layer_intercept_functions_type{},
682                                     function_names, function_count);
683
684    } else {
685        check_custom_functions(env.vulkan_functions, parent_type, dispatch_type, custom_functions_type{}, function_names,
686                               function_count);
687    }
688}
689
690// Device
691
692TEST(UnknownFunction, DeviceFromGDPA) { unknown_function_test_impl<VkDevice, VkDevice>({}); }
693
694TEST(UnknownFunction, DeviceFromGDPAWithLayerImplementation) {
695    unknown_function_test_impl<VkDevice, VkDevice>({TestConfig::add_layer_implementation});
696}
697
698TEST(UnknownFunction, DeviceFromGDPAWithLayerInterception) {
699    unknown_function_test_impl<VkDevice, VkDevice>({TestConfig::add_layer_interception});
700}
701
702TEST(UnknownFunction, DeviceFromGDPAWithLayerInterceptionAndLayerImplementation) {
703    unknown_function_test_impl<VkDevice, VkDevice>({TestConfig::add_layer_interception, TestConfig::add_layer_implementation});
704}
705
706TEST(UnknownFunction, DeviceFromGIPA) { unknown_function_test_impl<VkInstance, VkDevice>({}); }
707
708TEST(UnknownFunction, DeviceFromGIPAWithLayerImplementation) {
709    unknown_function_test_impl<VkInstance, VkDevice>({TestConfig::add_layer_implementation});
710}
711
712TEST(UnknownFunction, DeviceFromGIPAWithLayerInterception) {
713    unknown_function_test_impl<VkInstance, VkDevice>({TestConfig::add_layer_implementation});
714}
715
716TEST(UnknownFunction, DeviceFromGIPAWithLayerInterceptionAndLayerImplementation) {
717    unknown_function_test_impl<VkInstance, VkDevice>({TestConfig::add_layer_interception, TestConfig::add_layer_implementation});
718}
719
720// Command buffers
721
722TEST(UnknownFunction, CommandBufferFromGDPA) { unknown_function_test_impl<VkDevice, VkCommandBuffer>({}); }
723
724TEST(UnknownFunction, CommandBufferFromGDPAWithLayerImplementation) {
725    unknown_function_test_impl<VkDevice, VkCommandBuffer>({TestConfig::add_layer_implementation});
726}
727
728TEST(UnknownFunction, CommandBufferFromGDPAWithLayerInterception) {
729    unknown_function_test_impl<VkDevice, VkCommandBuffer>({TestConfig::add_layer_interception});
730}
731
732TEST(UnknownFunction, CommandBufferFromGDPAWithLayerInterceptionAndLayerImplementation) {
733    unknown_function_test_impl<VkDevice, VkCommandBuffer>(
734        {TestConfig::add_layer_interception, TestConfig::add_layer_implementation});
735}
736
737TEST(UnknownFunction, CommandBufferFromGIPA) { unknown_function_test_impl<VkInstance, VkCommandBuffer>({}); }
738
739TEST(UnknownFunction, CommandBufferFromGIPAWithLayerImplementation) {
740    unknown_function_test_impl<VkInstance, VkCommandBuffer>({TestConfig::add_layer_implementation});
741}
742
743TEST(UnknownFunction, CommandBufferFromGIPAWithLayerInterception) {
744    unknown_function_test_impl<VkInstance, VkCommandBuffer>({TestConfig::add_layer_implementation});
745}
746
747TEST(UnknownFunction, CommandBufferFromGIPAWithLayerInterceptionAndLayerImplementation) {
748    unknown_function_test_impl<VkInstance, VkCommandBuffer>(
749        {TestConfig::add_layer_interception, TestConfig::add_layer_implementation});
750}
751
752// Queues
753
754TEST(UnknownFunction, QueueFromGDPA) { unknown_function_test_impl<VkDevice, VkQueue>({}); }
755
756TEST(UnknownFunction, QueueFromGDPAWithLayerImplementation) {
757    unknown_function_test_impl<VkDevice, VkQueue>({TestConfig::add_layer_implementation});
758}
759
760TEST(UnknownFunction, QueueFromGDPAWithLayerInterception) {
761    unknown_function_test_impl<VkDevice, VkQueue>({TestConfig::add_layer_interception});
762}
763
764TEST(UnknownFunction, QueueFromGDPAWithLayerInterceptionAndLayerImplementation) {
765    unknown_function_test_impl<VkDevice, VkQueue>({TestConfig::add_layer_interception, TestConfig::add_layer_implementation});
766}
767
768TEST(UnknownFunction, QueueFromGIPA) { unknown_function_test_impl<VkInstance, VkQueue>({}); }
769
770TEST(UnknownFunction, QueueFromGIPAWithLayer) {
771    unknown_function_test_impl<VkInstance, VkQueue>({TestConfig::add_layer_implementation});
772}
773
774TEST(UnknownFunction, QueueFromGIPAWithLayerInterception) {
775    unknown_function_test_impl<VkInstance, VkQueue>({TestConfig::add_layer_implementation});
776}
777
778TEST(UnknownFunction, QueueFromGIPAWithLayerInterceptionAndLayerImplementation) {
779    unknown_function_test_impl<VkInstance, VkQueue>({TestConfig::add_layer_interception, TestConfig::add_layer_implementation});
780}
781
782/*
783 The purpose of LayerInterceptData is to provide a place to store data that is accessible inside the interception function.
784 It works by being a templated type with static variables. Every unique type used creates a new template instantiation, with its own
785 static variable storage. Thus interception functions that are templated correctly have per-template static data storage at their
786 disposal, which is used to query the next function in the chain and call down.
787*/
788
789template <typename UniqueType>
790struct LayerInterceptData {
791    static TestLayer* layer;
792    static const char* name;
793};
794template <typename UniqueType>
795TestLayer* LayerInterceptData<UniqueType>::layer = nullptr;
796template <typename UniqueType>
797const char* LayerInterceptData<UniqueType>::name = nullptr;
798
799template <typename DispatchableHandle>
800struct FunctionZero {
801    static VKAPI_ATTR uint32_t VKAPI_CALL implementation(DispatchableHandle, uint32_t a, uint32_t b) { return a + b; }
802
803    template <typename LayerType>
804    static VKAPI_ATTR uint32_t VKAPI_CALL intercept(DispatchableHandle handle, uint32_t a, uint32_t b) {
805        decltype(implementation)* func =
806            reinterpret_cast<decltype(&implementation)>(LayerType::layer->get_custom_intercept_function(LayerType::name));
807        if (func == nullptr) return 1337;
808        return func(handle, a + 3, b + 7);
809    }
810
811    template <typename ParentType>
812    static void check(VulkanFunctions const& loader, ParentType parent, DispatchableHandle dispatch_type, const char* name,
813                      uint32_t interception_count = 1) {
814        decltype(implementation)* returned_func = loader.load(parent, name);
815        ASSERT_NE(returned_func, nullptr);
816        EXPECT_EQ(returned_func(dispatch_type, 4, 9), (4 + 3 * interception_count) + (9 + 7 * interception_count));
817    }
818    template <typename ParentType>
819    static void check_no_implementation(VulkanFunctions const& loader, ParentType parent, DispatchableHandle dispatch_type,
820                                        const char* name) {
821        decltype(implementation)* returned_func = loader.load(parent, name);
822        ASSERT_NE(returned_func, nullptr);
823        EXPECT_EQ(returned_func(dispatch_type, 5, 2), 1337U);
824    }
825};
826
827template <typename DispatchableHandle>
828struct FunctionOne {
829    static VKAPI_ATTR uint32_t VKAPI_CALL implementation(DispatchableHandle, uint32_t a, uint32_t b, char c) { return a + b + c; }
830
831    template <typename LayerType>
832    static VKAPI_ATTR uint32_t VKAPI_CALL intercept(DispatchableHandle handle, uint32_t a, uint32_t b, char c) {
833        decltype(implementation)* func =
834            reinterpret_cast<decltype(&implementation)>(LayerType::layer->get_custom_intercept_function(LayerType::name));
835        if (func == nullptr) return 1337;
836        return func(handle, a + 2, b + 9, c + 1);
837    }
838
839    template <typename ParentType>
840    static void check(VulkanFunctions const& loader, ParentType parent, DispatchableHandle dispatch_type, const char* name,
841                      uint32_t interception_count = 1) {
842        decltype(implementation)* returned_func = loader.load(parent, name);
843        ASSERT_NE(returned_func, nullptr);
844        EXPECT_EQ(returned_func(dispatch_type, 12, 17, 'a'),
845                  (12 + 2 * interception_count) + (17 + 9 * interception_count) + ('a' + 1 * interception_count));
846    }
847    template <typename ParentType>
848    static void check_no_implementation(VulkanFunctions const& loader, ParentType parent, DispatchableHandle dispatch_type,
849                                        const char* name) {
850        decltype(implementation)* returned_func = loader.load(parent, name);
851        ASSERT_NE(returned_func, nullptr);
852        EXPECT_EQ(returned_func(dispatch_type, 1, 516, 'c'), 1337U);
853    }
854};
855
856template <typename DispatchableHandle>
857struct FunctionTwo {
858    static VKAPI_ATTR float VKAPI_CALL implementation(DispatchableHandle, int* ptr_a, int* ptr_b) {
859        return 0.123f + *ptr_a + *ptr_b;
860    }
861
862    template <typename LayerType>
863    static VKAPI_ATTR float VKAPI_CALL intercept(DispatchableHandle handle, int* ptr_a, int* ptr_b) {
864        decltype(implementation)* func =
865            reinterpret_cast<decltype(&implementation)>(LayerType::layer->get_custom_intercept_function(LayerType::name));
866        if (func == nullptr) return -1337.f;
867        *ptr_a += 2;
868        *ptr_b += 5;
869        return func(handle, ptr_a, ptr_b);
870    }
871
872    template <typename ParentType>
873    static void check(VulkanFunctions const& loader, ParentType parent, DispatchableHandle dispatch_type, const char* name,
874                      uint32_t interception_count = 1) {
875        decltype(implementation)* returned_func = loader.load(parent, name);
876        ASSERT_NE(returned_func, nullptr);
877        int x = 10, y = 3;
878        EXPECT_NEAR(returned_func(dispatch_type, &x, &y), 0.123f + (10 + 2 * interception_count) + (3 + 5 * interception_count),
879                    0.001);
880    }
881    template <typename ParentType>
882    static void check_no_implementation(VulkanFunctions const& loader, ParentType parent, DispatchableHandle dispatch_type,
883                                        const char* name) {
884        decltype(implementation)* returned_func = loader.load(parent, name);
885        ASSERT_NE(returned_func, nullptr);
886        int x = 10, y = 0;
887        EXPECT_NEAR(returned_func(dispatch_type, &x, &y), -1337.f, 0.001);
888    }
889};
890
891template <typename DispatchableHandle>
892struct FunctionThree {
893    static VKAPI_ATTR float VKAPI_CALL implementation(DispatchableHandle, int* ptr_a, float* ptr_b, uint32_t c) {
894        return 0.456f + *ptr_a + *ptr_b + c;
895    }
896
897    template <typename LayerType>
898    static VKAPI_ATTR float VKAPI_CALL intercept(DispatchableHandle handle, int* ptr_a, float* ptr_b, uint32_t c) {
899        decltype(implementation)* func =
900            reinterpret_cast<decltype(&implementation)>(LayerType::layer->get_custom_intercept_function(LayerType::name));
901        if (func == nullptr) return -1837.f;
902        *ptr_a += 55;
903        *ptr_b += 5.98f;
904        return func(handle, ptr_a, ptr_b, c + 100);
905    }
906
907    template <typename ParentType>
908    static void check(VulkanFunctions const& loader, ParentType parent, DispatchableHandle dispatch_type, const char* name,
909                      uint32_t interception_count = 1) {
910        decltype(implementation)* returned_func = loader.load(parent, name);
911        ASSERT_NE(returned_func, nullptr);
912        int x = 96;
913        float y = 7;
914        EXPECT_NEAR(returned_func(dispatch_type, &x, &y, 30),
915                    0.456f + (96 + 55 * interception_count) + (7 + 5.98f * interception_count) + (30 + 100 * interception_count),
916                    0.001);
917    }
918    template <typename ParentType>
919    static void check_no_implementation(VulkanFunctions const& loader, ParentType parent, DispatchableHandle dispatch_type,
920                                        const char* name) {
921        decltype(implementation)* returned_func = loader.load(parent, name);
922        ASSERT_NE(returned_func, nullptr);
923        int x = 10;
924        float y = 0;
925        EXPECT_NEAR(returned_func(dispatch_type, &x, &y, 40), -1837.f, 0.001);
926    }
927};
928
929template <typename DispatchableHandle>
930struct FunctionFour {
931    static VKAPI_ATTR VkResult VKAPI_CALL implementation(DispatchableHandle, VkPhysicalDeviceLimits* limits, uint32_t* count,
932                                                         VkExtensionProperties* props) {
933        limits->nonCoherentAtomSize = 0x0000ABCD0000FEDCU;
934        if (props == nullptr) {
935            *count = 5;
936            return VK_INCOMPLETE;
937        } else {
938            for (uint32_t i = 0; i < *count; i++) {
939                props[i].specVersion = i;
940            }
941            return VK_SUCCESS;
942        }
943    }
944
945    template <typename LayerType>
946    static VKAPI_ATTR VkResult VKAPI_CALL intercept(DispatchableHandle handle, VkPhysicalDeviceLimits* limits, uint32_t* count,
947                                                    VkExtensionProperties* props) {
948        decltype(implementation)* func =
949            reinterpret_cast<decltype(&implementation)>(LayerType::layer->get_custom_intercept_function(LayerType::name));
950        if (func == nullptr) return VK_ERROR_DEVICE_LOST;
951        VkResult res = func(handle, limits, count, props);
952        if (props) {
953            for (uint32_t i = 5; i < *count; i++) {
954                props[i].specVersion = 1234 + i * 2;
955            }
956        } else if (count) {
957            *count += 1;
958        }
959        return res;
960    }
961
962    template <typename ParentType>
963    static void check(VulkanFunctions const& loader, ParentType parent, DispatchableHandle dispatch_type, const char* name,
964                      uint32_t interception_count = 1) {
965        decltype(implementation)* returned_func = loader.load(parent, name);
966        ASSERT_NE(returned_func, nullptr);
967        VkPhysicalDeviceLimits limits{};
968        uint32_t count = 0;
969        EXPECT_EQ(returned_func(dispatch_type, &limits, &count, nullptr), VK_INCOMPLETE);
970        EXPECT_EQ(count, 5 + interception_count);
971        std::vector<VkExtensionProperties> props(count, VkExtensionProperties{});
972        EXPECT_EQ(returned_func(dispatch_type, &limits, &count, props.data()), VK_SUCCESS);
973        for (uint32_t i = 0; i < 5; i++) {
974            EXPECT_EQ(props.at(i).specVersion, i);
975        }
976        for (uint32_t i = 5; i < interception_count; i++) {
977            EXPECT_EQ(props.at(i).specVersion, 1234 + i * 2);  // interception should do this
978        }
979    }
980    template <typename ParentType>
981    static void check_no_implementation(VulkanFunctions const& loader, ParentType parent, DispatchableHandle dispatch_type,
982                                        const char* name) {
983        decltype(implementation)* returned_func = loader.load(parent, name);
984        ASSERT_NE(returned_func, nullptr);
985        VkPhysicalDeviceLimits limits{};
986        EXPECT_EQ(returned_func(dispatch_type, &limits, nullptr, nullptr), VK_ERROR_DEVICE_LOST);
987    }
988};
989
990struct UnknownFunction {
991    std::string name;
992
993    bool has_implementation = false;
994    std::vector<uint32_t> interception_stack;
995
996    UnknownFunction() = default;
997    UnknownFunction(std::string name) : name(name) {}
998
999    template <typename FunctionType, typename ParentType, typename DispatchableHandle>
1000    void check(VulkanFunctions const& loader, ParentType parent, DispatchableHandle dispatch_type) {
1001        if (has_implementation) {
1002            // Find how many layers intercept this function, stop if any layer 'implements' the function, thus doesn't return
1003            uint32_t intercept_count = 0;
1004            for (auto const& elem : interception_stack) {
1005                if (elem == 1) break;
1006                intercept_count++;
1007            }
1008            FunctionType::Function::check(loader, parent, dispatch_type, name.c_str(), intercept_count);
1009        } else {
1010            FunctionType::Function::check_no_implementation(loader, parent, dispatch_type, name.c_str());
1011        }
1012    }
1013
1014    void push_layer_implementation() { interception_stack.push_back(1); }
1015    void push_layer_interception() { interception_stack.push_back(0); }
1016};
1017
1018// For VkDevice, VkCommandBuffer, & VkQueue
1019template <typename FunctionType, typename DispatchableHandle>
1020struct UnknownFunctionInfo {
1021    using Function = FunctionType;
1022
1023    static void add_to_driver(UnknownFunction& func, PhysicalDevice& physical_device) {
1024        physical_device.add_device_function({func.name.c_str(), to_vkVoidFunction(Function::implementation)});
1025        func.has_implementation = true;
1026    }
1027
1028    template <typename LayerStruct>
1029    static void add_to_layer(UnknownFunction& func, TestLayer& layer, LayerStruct) {
1030        LayerInterceptData<LayerStruct>::layer = &layer;
1031        LayerInterceptData<LayerStruct>::name = func.name.c_str();
1032        layer.add_custom_device_interception_function(
1033            func.name, to_vkVoidFunction(&Function::template intercept<LayerInterceptData<LayerStruct>>));
1034        func.push_layer_interception();
1035    }
1036
1037    static void add_implementation_to_layer(UnknownFunction& func, TestLayer& layer) {
1038        layer.add_custom_device_implementation_function({func.name.c_str(), to_vkVoidFunction(Function::implementation)});
1039        func.has_implementation = true;
1040        func.push_layer_implementation();
1041    }
1042};
1043
1044// Specialization for VkPhysicalDevice
1045
1046template <typename FunctionType>
1047struct UnknownFunctionInfo<FunctionType, VkPhysicalDevice> {
1048    using Function = FunctionType;
1049
1050    static void add_to_driver(UnknownFunction& func, PhysicalDevice& physical_device) {
1051        physical_device.add_custom_physical_device_function({func.name.c_str(), to_vkVoidFunction(Function::implementation)});
1052        func.has_implementation = true;
1053    }
1054
1055    template <typename LayerStruct>
1056    static void add_to_layer(UnknownFunction& func, TestLayer& layer, LayerStruct) {
1057        LayerInterceptData<LayerStruct>::layer = &layer;
1058        LayerInterceptData<LayerStruct>::name = func.name.c_str();
1059        layer.add_custom_physical_device_intercept_function(
1060            func.name, to_vkVoidFunction(&Function::template intercept<LayerInterceptData<LayerStruct>>));
1061        func.push_layer_interception();
1062    }
1063
1064    static void add_implementation_to_layer(UnknownFunction& func, TestLayer& layer) {
1065        layer.add_custom_physical_device_implementation_function({func.name.c_str(), to_vkVoidFunction(Function::implementation)});
1066        func.has_implementation = true;
1067        func.push_layer_implementation();
1068    }
1069};
1070
1071struct Functions {
1072    template <template <typename> class Function>
1073    struct HelperTypedef {
1074        using physical_device = UnknownFunctionInfo<Function<VkPhysicalDevice>, VkPhysicalDevice>;
1075        using device = UnknownFunctionInfo<Function<VkDevice>, VkDevice>;
1076        using command_buffer = UnknownFunctionInfo<Function<VkCommandBuffer>, VkCommandBuffer>;
1077        using queue = UnknownFunctionInfo<Function<VkQueue>, VkQueue>;
1078    };
1079
1080    using zero = HelperTypedef<FunctionZero>;
1081    using one = HelperTypedef<FunctionOne>;
1082    using two = HelperTypedef<FunctionTwo>;
1083    using three = HelperTypedef<FunctionThree>;
1084    using four = HelperTypedef<FunctionFour>;
1085};
1086
1087template <size_t I>
1088struct D {};
1089
1090TEST(UnknownFunction, PhysicalDeviceFunctionTwoLayerInterception) {
1091    FrameworkEnvironment env{};
1092    auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
1093    PhysicalDevice& pd = driver.physical_devices.back();
1094
1095    UnknownFunction f{"vkFunc1"};
1096    Functions::three::physical_device::add_to_driver(f, pd);
1097
1098    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
1099                                                         .set_name("VK_LAYER_implicit_layer_unknown_function_intercept")
1100                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
1101                                                         .set_disable_environment("DISABLE_ME")),
1102                           "implicit_layer_unknown_function_intercept.json");
1103    auto& layer0 = env.get_test_layer(0);
1104    Functions::three::physical_device::add_to_layer(f, layer0, D<0>{});
1105
1106    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
1107                                                         .set_name("VK_LAYER_implicit_layer_unknown_function_intercept2")
1108                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
1109                                                         .set_disable_environment("DISABLE_ME")),
1110                           "implicit_layer_unknown_function_intercept2.json");
1111    auto& layer1 = env.get_test_layer(1);
1112
1113    Functions::three::physical_device::add_to_layer(f, layer1, D<1>{});
1114
1115    InstWrapper inst{env.vulkan_functions};
1116    inst.CheckCreate();
1117
1118    VkPhysicalDevice phys_dev = inst.GetPhysDev();
1119
1120    f.check<Functions::three::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1121}
1122
1123TEST(UnknownFunction, ManyCombinations) {
1124    FrameworkEnvironment env{};
1125    auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
1126    PhysicalDevice& physical_device = driver.physical_devices.back();
1127    std::vector<UnknownFunction> unknown_funcs;
1128
1129    unknown_funcs.emplace_back("vkZero_uint32_uint32_0");
1130    unknown_funcs.emplace_back("vkOne_uint32_uint32_char_1");
1131    unknown_funcs.emplace_back("vkTwo_ptr_int_ptr_int_2");
1132    unknown_funcs.emplace_back("vkThree_ptr_int_ptr_float_uint_3");
1133    unknown_funcs.emplace_back("vkFour_PD_limits_ptr_uint_ptr_ExtProps_4");
1134    unknown_funcs.emplace_back("vkZero_uint32_uint32_5");
1135    unknown_funcs.emplace_back("vkOne_uint32_uint32_char_6");
1136    unknown_funcs.emplace_back("vkTwo_ptr_int_ptr_int_7");
1137    unknown_funcs.emplace_back("vkThree_ptr_int_ptr_float_uint_8");
1138    unknown_funcs.emplace_back("vkFour_PD_limits_ptr_uint_ptr_ExtProps_9");
1139    unknown_funcs.emplace_back("vkZero_uint32_uint32_10");
1140    unknown_funcs.emplace_back("vkOne_uint32_uint32_char_11");
1141    unknown_funcs.emplace_back("vkTwo_ptr_int_ptr_int_12");
1142
1143    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
1144                                                         .set_name("VK_LAYER_implicit_layer_unknown_function_intercept_0")
1145                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
1146                                                         .set_disable_environment("DISABLE_ME")
1147                                                         .add_device_extension(ManifestLayer::LayerDescription::Extension{
1148                                                             "VK_EXT_for_the_laughs", 0, {"vkOne_uint32_uint32_char_11"}})),
1149                           "implicit_layer_unknown_function_intercept_0.json");
1150    auto& layer_0 = env.get_test_layer(0);
1151    layer_0.set_use_gipa_GetPhysicalDeviceProcAddr(true);
1152    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
1153                                                         .set_name("VK_LAYER_implicit_layer_unknown_function_intercept_1")
1154                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
1155                                                         .set_disable_environment("DISABLE_ME")),
1156                           "implicit_layer_unknown_function_intercept_1.json");
1157    auto& layer_1 = env.get_test_layer(1);
1158    layer_1.set_use_gipa_GetPhysicalDeviceProcAddr(false);
1159
1160    // Physical Device functions
1161    Functions::zero::physical_device::add_to_driver(unknown_funcs.at(0), physical_device);
1162
1163    Functions::one::physical_device::add_to_driver(unknown_funcs.at(1), physical_device);
1164    Functions::one::physical_device::add_to_layer(unknown_funcs.at(1), layer_0, D<0>{});
1165
1166    Functions::two::physical_device::add_to_driver(unknown_funcs.at(2), physical_device);
1167    Functions::two::physical_device::add_to_layer(unknown_funcs.at(2), layer_1, D<1>{});
1168
1169    Functions::three::physical_device::add_to_driver(unknown_funcs.at(3), physical_device);
1170    Functions::three::physical_device::add_to_layer(unknown_funcs.at(3), layer_0, D<2>{});
1171    Functions::three::physical_device::add_to_layer(unknown_funcs.at(3), layer_1, D<3>{});
1172
1173    Functions::four::physical_device::add_implementation_to_layer(unknown_funcs.at(4), layer_0);
1174    Functions::four::physical_device::add_to_layer(unknown_funcs.at(4), layer_1, D<4>{});
1175
1176    Functions::zero::physical_device::add_to_layer(unknown_funcs.at(5), layer_0, D<5>{});
1177    Functions::zero::physical_device::add_implementation_to_layer(unknown_funcs.at(5), layer_1);
1178
1179    Functions::two::physical_device::add_to_driver(unknown_funcs.at(12), physical_device);
1180    Functions::zero::physical_device::add_to_layer(unknown_funcs.at(12), layer_0, D<12>{});
1181    Functions::zero::physical_device::add_implementation_to_layer(unknown_funcs.at(12), layer_1);
1182
1183    // Device functions
1184    Functions::one::device::add_to_driver(unknown_funcs.at(6), physical_device);
1185
1186    Functions::two::device::add_to_driver(unknown_funcs.at(7), physical_device);
1187    Functions::two::device::add_to_layer(unknown_funcs.at(7), layer_0, D<6>{});
1188
1189    Functions::three::device::add_to_driver(unknown_funcs.at(8), physical_device);
1190    Functions::three::device::add_to_layer(unknown_funcs.at(8), layer_1, D<7>{});
1191
1192    Functions::four::device::add_to_driver(unknown_funcs.at(9), physical_device);
1193    Functions::four::device::add_to_layer(unknown_funcs.at(9), layer_0, D<8>{});
1194    Functions::four::device::add_to_layer(unknown_funcs.at(9), layer_1, D<9>{});
1195
1196    Functions::zero::device::add_implementation_to_layer(unknown_funcs.at(10), layer_0);
1197    Functions::zero::device::add_to_layer(unknown_funcs.at(10), layer_1, D<10>{});
1198
1199    Functions::one::device::add_to_layer(unknown_funcs.at(11), layer_0, D<11>{});
1200    Functions::one::device::add_implementation_to_layer(unknown_funcs.at(11), layer_1);
1201
1202    {
1203        InstWrapper inst{env.vulkan_functions};
1204        inst.CheckCreate();
1205
1206        VkPhysicalDevice phys_dev = inst.GetPhysDev();
1207        DeviceWrapper dev{inst};
1208        dev.CheckCreate(phys_dev);
1209
1210        unknown_funcs.at(0).check<Functions::zero::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1211        unknown_funcs.at(1).check<Functions::one::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1212        unknown_funcs.at(2).check<Functions::two::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1213        unknown_funcs.at(3).check<Functions::three::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1214        unknown_funcs.at(4).check<Functions::four::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1215        unknown_funcs.at(5).check<Functions::zero::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1216
1217        // Check that GIPA works for device functions
1218        unknown_funcs.at(6).check<Functions::one::device>(env.vulkan_functions, inst.inst, dev.dev);
1219        unknown_funcs.at(7).check<Functions::two::device>(env.vulkan_functions, inst.inst, dev.dev);
1220        unknown_funcs.at(8).check<Functions::three::device>(env.vulkan_functions, inst.inst, dev.dev);
1221        unknown_funcs.at(9).check<Functions::four::device>(env.vulkan_functions, inst.inst, dev.dev);
1222        unknown_funcs.at(10).check<Functions::zero::device>(env.vulkan_functions, inst.inst, dev.dev);
1223        unknown_funcs.at(11).check<Functions::one::device>(env.vulkan_functions, inst.inst, dev.dev);
1224
1225        // Check that GDPA works for device functions
1226        unknown_funcs.at(6).check<Functions::one::device>(env.vulkan_functions, dev.dev, dev.dev);
1227        unknown_funcs.at(7).check<Functions::two::device>(env.vulkan_functions, dev.dev, dev.dev);
1228        unknown_funcs.at(8).check<Functions::three::device>(env.vulkan_functions, dev.dev, dev.dev);
1229        unknown_funcs.at(9).check<Functions::four::device>(env.vulkan_functions, dev.dev, dev.dev);
1230        unknown_funcs.at(10).check<Functions::zero::device>(env.vulkan_functions, dev.dev, dev.dev);
1231        unknown_funcs.at(11).check<Functions::one::device>(env.vulkan_functions, dev.dev, dev.dev);
1232    }
1233
1234    {
1235        InstWrapper inst{env.vulkan_functions};
1236        inst.CheckCreate();
1237
1238        VkPhysicalDevice phys_dev = inst.GetPhysDev();
1239        DeviceWrapper dev{inst};
1240        dev.CheckCreate(phys_dev);
1241        // Load device functions first, to make sure order of function loading is not important
1242        // Check that GIPA works for device functions
1243        unknown_funcs.at(6).check<Functions::one::device>(env.vulkan_functions, inst.inst, dev.dev);
1244        unknown_funcs.at(7).check<Functions::two::device>(env.vulkan_functions, inst.inst, dev.dev);
1245        unknown_funcs.at(8).check<Functions::three::device>(env.vulkan_functions, inst.inst, dev.dev);
1246        unknown_funcs.at(9).check<Functions::four::device>(env.vulkan_functions, inst.inst, dev.dev);
1247        unknown_funcs.at(10).check<Functions::zero::device>(env.vulkan_functions, inst.inst, dev.dev);
1248        unknown_funcs.at(11).check<Functions::one::device>(env.vulkan_functions, inst.inst, dev.dev);
1249
1250        // Check that GDPA works for device functions
1251        unknown_funcs.at(6).check<Functions::one::device>(env.vulkan_functions, dev.dev, dev.dev);
1252        unknown_funcs.at(7).check<Functions::two::device>(env.vulkan_functions, dev.dev, dev.dev);
1253        unknown_funcs.at(8).check<Functions::three::device>(env.vulkan_functions, dev.dev, dev.dev);
1254        unknown_funcs.at(9).check<Functions::four::device>(env.vulkan_functions, dev.dev, dev.dev);
1255        unknown_funcs.at(10).check<Functions::zero::device>(env.vulkan_functions, dev.dev, dev.dev);
1256        unknown_funcs.at(11).check<Functions::one::device>(env.vulkan_functions, dev.dev, dev.dev);
1257
1258        unknown_funcs.at(0).check<Functions::zero::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1259        unknown_funcs.at(1).check<Functions::one::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1260        unknown_funcs.at(2).check<Functions::two::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1261        unknown_funcs.at(3).check<Functions::three::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1262        unknown_funcs.at(4).check<Functions::four::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1263        unknown_funcs.at(5).check<Functions::zero::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1264    }
1265}
1266
1267TEST(UnknownFunction, PhysicalDeviceFunctionInLayer) {
1268    FrameworkEnvironment env{};
1269    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
1270
1271    env.add_implicit_layer(ManifestLayer{}
1272                               .add_layer(ManifestLayer::LayerDescription{}
1273                                              .set_name("VK_LAYER_implicit_layer_1")
1274                                              .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_0)
1275                                              .set_disable_environment("DISABLE_ME"))
1276                               .set_file_format_version({1, 0, 0}),
1277                           "implicit_layer_1.json");
1278
1279    UnknownFunction unknown_func{"vkPhysicalDeviceFunctionInLayer"};
1280    const char* ext_name = "VK_EXT_not_funny";
1281
1282    const char* explicit_layer_unknown_function_implement = "VK_LAYER_implement_unknown_function";
1283    env.add_explicit_layer(
1284        ManifestLayer{}
1285            .add_layer(ManifestLayer::LayerDescription{}
1286                           .set_name(explicit_layer_unknown_function_implement)
1287                           .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
1288                           .add_instance_extension(ManifestLayer::LayerDescription::Extension{ext_name, 0, {unknown_func.name}}))
1289            .set_file_format_version({1, 1, 0}),
1290        "implement_unknown_function.json");
1291    auto& layer0 = env.get_test_layer(1);
1292
1293    const char* explicit_layer_to_enable_1 = "VK_LAYER_explicit_layer_1";
1294    env.add_explicit_layer(ManifestLayer{}
1295                               .add_layer(ManifestLayer::LayerDescription{}
1296                                              .set_name(explicit_layer_to_enable_1)
1297                                              .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2))
1298                               .set_file_format_version({1, 2, 0}),
1299                           "explicit_layer_2.json");
1300
1301    Functions::four::physical_device::add_implementation_to_layer(unknown_func, layer0);
1302
1303    InstWrapper inst{env.vulkan_functions};
1304    inst.create_info.add_layer(explicit_layer_to_enable_1);
1305    inst.create_info.add_layer(explicit_layer_unknown_function_implement);
1306    inst.CheckCreate();
1307
1308    VkPhysicalDevice phys_dev = inst.GetPhysDev();
1309
1310    unknown_func.check<Functions::four::physical_device>(env.vulkan_functions, inst.inst, phys_dev);
1311}
1312