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