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