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
32 enum class TestConfig {
33 add_layer_implementation,
34 add_layer_interception,
35 };
36
has_flag(std::vector<TestConfig> const& flags, TestConfig config)37 bool 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 */
49 template <typename DispatchableHandleType>
50 struct custom_functions {
func_zerocustom_functions51 static VKAPI_ATTR uint32_t VKAPI_CALL func_zero(DispatchableHandleType, uint32_t foo) { return foo; };
func_onecustom_functions52 static VKAPI_ATTR uint32_t VKAPI_CALL func_one(DispatchableHandleType, uint32_t foo, uint32_t bar) { return foo + bar; };
func_twocustom_functions53 static VKAPI_ATTR float VKAPI_CALL func_two(DispatchableHandleType, uint32_t foo, uint32_t bar, float baz) {
54 return baz + foo + bar;
55 };
func_threecustom_functions56 static VKAPI_ATTR int VKAPI_CALL func_three(DispatchableHandleType, int* ptr_a, int* ptr_b) { return *ptr_a + *ptr_b; };
func_fourcustom_functions57 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 /*
64 Functions for testing of layer interception of unknown functions. Note the need to pass a pointer to the layer and the name
65 of the called function as a parameter, this is necessary to allow a generic layer implementation, as the layer must look up
66 the function pointer to use. A real layer would store the function pointer in a dedicated structure per-instance/device, but
67 since the TestLayer is a generic layer, there isn't a fixed list of functions that should be supported.
68 */
69
find_custom_func(TestLayer* layer, const char* name)70 PFN_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
77 template <typename DispatchableHandleType>
78 struct layer_intercept_functions {
func_zerolayer_intercept_functions79 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 }
func_onelayer_intercept_functions84 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 }
func_twolayer_intercept_functions90 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 };
func_threelayer_intercept_functions96 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 };
func_fourlayer_intercept_functions104 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
112 template <typename DispatchableHandleType>
113 struct layer_implementation_functions {
func_zerolayer_implementation_functions114 static VKAPI_ATTR uint32_t VKAPI_CALL func_zero(DispatchableHandleType, TestLayer*, const char*, uint32_t i) { return i * 3; }
func_onelayer_implementation_functions115 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 }
func_twolayer_implementation_functions118 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 };
func_threelayer_implementation_functions122 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 };
func_fourlayer_implementation_functions125 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
add_function_names(std::vector<std::string>& func_names, uint32_t function_count, uint32_t function_start = 0)133 void 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.
145 template <typename FunctionStruct>
fill_implementation_functions(std::vector<VulkanFunction>& function_list, std::vector<std::string>& func_names, FunctionStruct const& funcs, uint32_t function_count, uint32_t function_start = 0)146 void 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
159 template <typename FunctionStruct>
fill_device_intercept_functions(TestLayer& layer, std::vector<std::string>& func_names, FunctionStruct const& funcs, uint32_t function_count, uint32_t function_start = 0)160 void 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
172 template <typename FunctionStruct>
fill_phys_dev_intercept_functions(TestLayer& layer, std::vector<std::string>& func_names, FunctionStruct const& funcs, uint32_t function_count, uint32_t function_start = 0)173 void 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
184 template <typename FunctionLoader, typename ParentType, typename DispatchableHandleType, typename FunctionStruct>
check_custom_functions(FunctionLoader& loader, ParentType parent, DispatchableHandleType handle, FunctionStruct const&, std::vector<std::string>& func_names, uint32_t function_count, uint32_t function_start = 0)185 void 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
215 template <typename FunctionLoader, typename ParentType, typename DispatchableHandleType, typename FunctionStruct>
check_layer_custom_functions(FunctionLoader& loader, ParentType parent, DispatchableHandleType handle, TestLayer& layer, FunctionStruct const&, std::vector<std::string>& func_names, uint32_t function_count, uint32_t function_start = 0)216 void 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
255 template <typename FunctionLoader, typename ParentType, typename DispatchableHandleType, typename FunctionStruct>
check_layer_custom_functions_no_implementation(FunctionLoader& loader, ParentType parent, DispatchableHandleType handle, TestLayer& layer, FunctionStruct const&, std::vector<std::string>& func_names, uint32_t function_count, uint32_t function_start = 0)256 void 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
293 template <typename FunctionLoader, typename ParentType, typename DispatchableHandleType, typename FunctionStruct>
check_layer_custom_functions_no_interception(FunctionLoader& loader, ParentType parent, DispatchableHandleType handle, TestLayer& layer, FunctionStruct const&, std::vector<std::string>& func_names, uint32_t function_count, uint32_t function_start = 0)294 void 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
332 using custom_physical_device_functions = custom_functions<VkPhysicalDevice>;
333 using layer_intercept_physical_device_functions = layer_intercept_functions<VkPhysicalDevice>;
334 using layer_implementation_physical_device_functions = layer_implementation_functions<VkPhysicalDevice>;
335
TEST(UnknownFunction, PhysicalDeviceFunction)336 TEST(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
TEST(UnknownFunction, PhysicalDeviceFunctionMultipleDriverSupport)353 TEST(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.
TEST(UnknownFunctionDeathTests, PhysicalDeviceFunctionErrorPath)392 TEST(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
TEST(UnknownFunction, PhysicalDeviceFunctionWithImplicitLayerImplementation)424 TEST(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
TEST(UnknownFunction, PhysicalDeviceFunctionMultipleDriverSupportWithImplicitLayerImplementation)448 TEST(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
TEST(UnknownFunction, PhysicalDeviceFunctionWithImplicitLayerInterception)492 TEST(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
TEST(UnknownFunction, PhysicalDeviceFunctionDriverSupportWithImplicitLayerInterception)516 TEST(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
TEST(UnknownFunction, PhysicalDeviceFunctionWithMultipleImplicitLayersInterception)540 TEST(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
580 template <typename ParentType>
581 ParentType get_parent_type(InstWrapper const& inst, DeviceWrapper const& dev);
582
583 template <>
get_parent_type(InstWrapper const& inst, DeviceWrapper const&)584 VkInstance get_parent_type<VkInstance>(InstWrapper const& inst, DeviceWrapper const&) {
585 return inst.inst;
586 }
587 template <>
get_parent_type(InstWrapper const&, DeviceWrapper const& dev)588 VkDevice get_parent_type<VkDevice>(InstWrapper const&, DeviceWrapper const& dev) {
589 return dev.dev;
590 }
591
592 template <typename DispatchableHandleType>
593 DispatchableHandleType get_dispatch_handle(FrameworkEnvironment& env, DeviceWrapper const& dev,
594 std::vector<TestConfig> const& flags);
595
596 template <>
get_dispatch_handle(FrameworkEnvironment&, DeviceWrapper const& dev, std::vector<TestConfig> const&)597 VkDevice get_dispatch_handle<VkDevice>(FrameworkEnvironment&, DeviceWrapper const& dev, std::vector<TestConfig> const&) {
598 return dev.dev;
599 }
600
601 template <>
get_dispatch_handle(FrameworkEnvironment& env, DeviceWrapper const& dev, std::vector<TestConfig> const&)602 VkCommandBuffer 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
616 template <>
get_dispatch_handle(FrameworkEnvironment& env, DeviceWrapper const& dev, std::vector<TestConfig> const&)617 VkQueue 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
624 template <typename ParentType, typename DispatchableHandleType>
unknown_function_test_impl(std::vector<TestConfig> const& flags)625 void 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
TEST(UnknownFunction, DeviceFromGDPA)692 TEST(UnknownFunction, DeviceFromGDPA) { unknown_function_test_impl<VkDevice, VkDevice>({}); }
693
TEST(UnknownFunction, DeviceFromGDPAWithLayerImplementation)694 TEST(UnknownFunction, DeviceFromGDPAWithLayerImplementation) {
695 unknown_function_test_impl<VkDevice, VkDevice>({TestConfig::add_layer_implementation});
696 }
697
TEST(UnknownFunction, DeviceFromGDPAWithLayerInterception)698 TEST(UnknownFunction, DeviceFromGDPAWithLayerInterception) {
699 unknown_function_test_impl<VkDevice, VkDevice>({TestConfig::add_layer_interception});
700 }
701
TEST(UnknownFunction, DeviceFromGDPAWithLayerInterceptionAndLayerImplementation)702 TEST(UnknownFunction, DeviceFromGDPAWithLayerInterceptionAndLayerImplementation) {
703 unknown_function_test_impl<VkDevice, VkDevice>({TestConfig::add_layer_interception, TestConfig::add_layer_implementation});
704 }
705
TEST(UnknownFunction, DeviceFromGIPA)706 TEST(UnknownFunction, DeviceFromGIPA) { unknown_function_test_impl<VkInstance, VkDevice>({}); }
707
TEST(UnknownFunction, DeviceFromGIPAWithLayerImplementation)708 TEST(UnknownFunction, DeviceFromGIPAWithLayerImplementation) {
709 unknown_function_test_impl<VkInstance, VkDevice>({TestConfig::add_layer_implementation});
710 }
711
TEST(UnknownFunction, DeviceFromGIPAWithLayerInterception)712 TEST(UnknownFunction, DeviceFromGIPAWithLayerInterception) {
713 unknown_function_test_impl<VkInstance, VkDevice>({TestConfig::add_layer_implementation});
714 }
715
TEST(UnknownFunction, DeviceFromGIPAWithLayerInterceptionAndLayerImplementation)716 TEST(UnknownFunction, DeviceFromGIPAWithLayerInterceptionAndLayerImplementation) {
717 unknown_function_test_impl<VkInstance, VkDevice>({TestConfig::add_layer_interception, TestConfig::add_layer_implementation});
718 }
719
720 // Command buffers
721
TEST(UnknownFunction, CommandBufferFromGDPA)722 TEST(UnknownFunction, CommandBufferFromGDPA) { unknown_function_test_impl<VkDevice, VkCommandBuffer>({}); }
723
TEST(UnknownFunction, CommandBufferFromGDPAWithLayerImplementation)724 TEST(UnknownFunction, CommandBufferFromGDPAWithLayerImplementation) {
725 unknown_function_test_impl<VkDevice, VkCommandBuffer>({TestConfig::add_layer_implementation});
726 }
727
TEST(UnknownFunction, CommandBufferFromGDPAWithLayerInterception)728 TEST(UnknownFunction, CommandBufferFromGDPAWithLayerInterception) {
729 unknown_function_test_impl<VkDevice, VkCommandBuffer>({TestConfig::add_layer_interception});
730 }
731
TEST(UnknownFunction, CommandBufferFromGDPAWithLayerInterceptionAndLayerImplementation)732 TEST(UnknownFunction, CommandBufferFromGDPAWithLayerInterceptionAndLayerImplementation) {
733 unknown_function_test_impl<VkDevice, VkCommandBuffer>(
734 {TestConfig::add_layer_interception, TestConfig::add_layer_implementation});
735 }
736
TEST(UnknownFunction, CommandBufferFromGIPA)737 TEST(UnknownFunction, CommandBufferFromGIPA) { unknown_function_test_impl<VkInstance, VkCommandBuffer>({}); }
738
TEST(UnknownFunction, CommandBufferFromGIPAWithLayerImplementation)739 TEST(UnknownFunction, CommandBufferFromGIPAWithLayerImplementation) {
740 unknown_function_test_impl<VkInstance, VkCommandBuffer>({TestConfig::add_layer_implementation});
741 }
742
TEST(UnknownFunction, CommandBufferFromGIPAWithLayerInterception)743 TEST(UnknownFunction, CommandBufferFromGIPAWithLayerInterception) {
744 unknown_function_test_impl<VkInstance, VkCommandBuffer>({TestConfig::add_layer_implementation});
745 }
746
TEST(UnknownFunction, CommandBufferFromGIPAWithLayerInterceptionAndLayerImplementation)747 TEST(UnknownFunction, CommandBufferFromGIPAWithLayerInterceptionAndLayerImplementation) {
748 unknown_function_test_impl<VkInstance, VkCommandBuffer>(
749 {TestConfig::add_layer_interception, TestConfig::add_layer_implementation});
750 }
751
752 // Queues
753
TEST(UnknownFunction, QueueFromGDPA)754 TEST(UnknownFunction, QueueFromGDPA) { unknown_function_test_impl<VkDevice, VkQueue>({}); }
755
TEST(UnknownFunction, QueueFromGDPAWithLayerImplementation)756 TEST(UnknownFunction, QueueFromGDPAWithLayerImplementation) {
757 unknown_function_test_impl<VkDevice, VkQueue>({TestConfig::add_layer_implementation});
758 }
759
TEST(UnknownFunction, QueueFromGDPAWithLayerInterception)760 TEST(UnknownFunction, QueueFromGDPAWithLayerInterception) {
761 unknown_function_test_impl<VkDevice, VkQueue>({TestConfig::add_layer_interception});
762 }
763
TEST(UnknownFunction, QueueFromGDPAWithLayerInterceptionAndLayerImplementation)764 TEST(UnknownFunction, QueueFromGDPAWithLayerInterceptionAndLayerImplementation) {
765 unknown_function_test_impl<VkDevice, VkQueue>({TestConfig::add_layer_interception, TestConfig::add_layer_implementation});
766 }
767
TEST(UnknownFunction, QueueFromGIPA)768 TEST(UnknownFunction, QueueFromGIPA) { unknown_function_test_impl<VkInstance, VkQueue>({}); }
769
TEST(UnknownFunction, QueueFromGIPAWithLayer)770 TEST(UnknownFunction, QueueFromGIPAWithLayer) {
771 unknown_function_test_impl<VkInstance, VkQueue>({TestConfig::add_layer_implementation});
772 }
773
TEST(UnknownFunction, QueueFromGIPAWithLayerInterception)774 TEST(UnknownFunction, QueueFromGIPAWithLayerInterception) {
775 unknown_function_test_impl<VkInstance, VkQueue>({TestConfig::add_layer_implementation});
776 }
777
TEST(UnknownFunction, QueueFromGIPAWithLayerInterceptionAndLayerImplementation)778 TEST(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
789 template <typename UniqueType>
790 struct LayerInterceptData {
791 static TestLayer* layer;
792 static const char* name;
793 };
794 template <typename UniqueType>
795 TestLayer* LayerInterceptData<UniqueType>::layer = nullptr;
796 template <typename UniqueType>
797 const char* LayerInterceptData<UniqueType>::name = nullptr;
798
799 template <typename DispatchableHandle>
800 struct FunctionZero {
implementationFunctionZero801 static VKAPI_ATTR uint32_t VKAPI_CALL implementation(DispatchableHandle, uint32_t a, uint32_t b) { return a + b; }
802
803 template <typename LayerType>
interceptFunctionZero804 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>
checkFunctionZero812 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>
check_no_implementationFunctionZero819 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
827 template <typename DispatchableHandle>
828 struct FunctionOne {
implementationFunctionOne829 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>
interceptFunctionOne832 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>
checkFunctionOne840 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>
check_no_implementationFunctionOne848 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
856 template <typename DispatchableHandle>
857 struct FunctionTwo {
implementationFunctionTwo858 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>
interceptFunctionTwo863 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>
checkFunctionTwo873 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>
check_no_implementationFunctionTwo882 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
891 template <typename DispatchableHandle>
892 struct FunctionThree {
implementationFunctionThree893 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>
interceptFunctionThree898 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>
checkFunctionThree908 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>
check_no_implementationFunctionThree919 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
929 template <typename DispatchableHandle>
930 struct FunctionFour {
implementationFunctionFour931 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>
interceptFunctionFour946 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>
checkFunctionFour963 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>
check_no_implementationFunctionFour981 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
990 struct UnknownFunction {
991 std::string name;
992
993 bool has_implementation = false;
994 std::vector<uint32_t> interception_stack;
995
996 UnknownFunction() = default;
UnknownFunctionUnknownFunction997 UnknownFunction(std::string name) : name(name) {}
998
999 template <typename FunctionType, typename ParentType, typename DispatchableHandle>
checkUnknownFunction1000 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
push_layer_implementationUnknownFunction1014 void push_layer_implementation() { interception_stack.push_back(1); }
push_layer_interceptionUnknownFunction1015 void push_layer_interception() { interception_stack.push_back(0); }
1016 };
1017
1018 // For VkDevice, VkCommandBuffer, & VkQueue
1019 template <typename FunctionType, typename DispatchableHandle>
1020 struct UnknownFunctionInfo {
1021 using Function = FunctionType;
1022
add_to_driverUnknownFunctionInfo1023 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>
add_to_layerUnknownFunctionInfo1029 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
add_implementation_to_layerUnknownFunctionInfo1037 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
1046 template <typename FunctionType>
1047 struct UnknownFunctionInfo<FunctionType, VkPhysicalDevice> {
1048 using Function = FunctionType;
1049
add_to_driverUnknownFunctionInfo1050 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>
add_to_layerUnknownFunctionInfo1056 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
add_implementation_to_layerUnknownFunctionInfo1064 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
1071 struct 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
1087 template <size_t I>
1088 struct D {};
1089
TEST(UnknownFunction, PhysicalDeviceFunctionTwoLayerInterception)1090 TEST(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
TEST(UnknownFunction, ManyCombinations)1123 TEST(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
TEST(UnknownFunction, PhysicalDeviceFunctionInLayer)1267 TEST(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