1/*
2 * Copyright (c) 2021-2022 The Khronos Group Inc.
3 * Copyright (c) 2021-2022 Valve Corporation
4 * Copyright (c) 2021-2022 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// Verify that the various ways to get vkGetInstanceProcAddr return the same value
31TEST(GetProcAddr, VerifyGetInstanceProcAddr) {
32    FrameworkEnvironment env{};
33    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device("physical_device_0");
34    {
35        InstWrapper inst{env.vulkan_functions};
36        inst.create_info.set_api_version(VK_API_VERSION_1_1);
37        inst.CheckCreate();
38
39        // NOTE: The vulkan_functions are queried using the platform get proc addr from the loader.  So we'll compare
40        //       that to what is returned by asking it what the various Vulkan get proc addr functions are.
41        PFN_vkGetInstanceProcAddr gipa_loader = env.vulkan_functions.vkGetInstanceProcAddr;
42        PFN_vkGetInstanceProcAddr gipa_queried = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
43            env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkGetInstanceProcAddr"));
44        ASSERT_EQ(gipa_loader, gipa_queried);
45    }
46
47    {
48        InstWrapper inst{env.vulkan_functions};
49        inst.create_info.set_api_version(VK_API_VERSION_1_3);
50        inst.CheckCreate();
51
52        // NOTE: The vulkan_functions are queried using the platform get proc addr from the loader.  So we'll compare
53        //       that to what is returned by asking it what the various Vulkan get proc addr functions are.
54        PFN_vkGetInstanceProcAddr gipa_loader = env.vulkan_functions.vkGetInstanceProcAddr;
55        PFN_vkGetInstanceProcAddr gipa_queried = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
56            env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkGetInstanceProcAddr"));
57        ASSERT_EQ(gipa_loader, gipa_queried);
58    }
59}
60
61// Verify that the various ways to get vkGetDeviceProcAddr return the same value
62TEST(GetProcAddr, VerifyGetDeviceProcAddr) {
63    FrameworkEnvironment env{};
64    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device("physical_device_0");
65
66    InstWrapper inst{env.vulkan_functions};
67    inst.create_info.set_api_version(VK_API_VERSION_1_1);
68    inst.CheckCreate();
69    VkPhysicalDevice phys_dev = inst.GetPhysDev();
70
71    // NOTE: The vulkan_functions are queried using the platform get proc addr from the loader.  So we'll compare
72    //       that to what is returned by asking it what the various Vulkan get proc addr functions are.
73    PFN_vkGetDeviceProcAddr gdpa_loader = env.vulkan_functions.vkGetDeviceProcAddr;
74    PFN_vkGetDeviceProcAddr gdpa_inst_queried = inst.load("vkGetDeviceProcAddr");
75    ASSERT_EQ(gdpa_loader, gdpa_inst_queried);
76
77    DeviceWrapper dev{inst};
78    dev.CheckCreate(phys_dev);
79
80    PFN_vkGetDeviceProcAddr gdpa_dev_queried = dev.load("vkGetDeviceProcAddr");
81    ASSERT_EQ(gdpa_loader, gdpa_dev_queried);
82}
83
84// Load the global function pointers with and without a NULL vkInstance handle.
85// Call the function to make sure it is callable, don't care about what is returned.
86TEST(GetProcAddr, GlobalFunctions) {
87    FrameworkEnvironment env{};
88    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device("physical_device_0");
89
90    auto& gipa = env.vulkan_functions.vkGetInstanceProcAddr;
91    // global entry points with NULL instance handle
92    {
93        auto EnumerateInstanceExtensionProperties =
94            reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(gipa(NULL, "vkEnumerateInstanceExtensionProperties"));
95        handle_assert_has_value(EnumerateInstanceExtensionProperties);
96        uint32_t ext_count = 0;
97        ASSERT_EQ(VK_SUCCESS, EnumerateInstanceExtensionProperties("", &ext_count, nullptr));
98
99        auto EnumerateInstanceLayerProperties =
100            reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(gipa(NULL, "vkEnumerateInstanceLayerProperties"));
101        handle_assert_has_value(EnumerateInstanceLayerProperties);
102        uint32_t layer_count = 0;
103        ASSERT_EQ(VK_SUCCESS, EnumerateInstanceLayerProperties(&layer_count, nullptr));
104
105        auto EnumerateInstanceVersion = reinterpret_cast<PFN_vkEnumerateInstanceVersion>(gipa(NULL, "vkEnumerateInstanceVersion"));
106        handle_assert_has_value(EnumerateInstanceVersion);
107        uint32_t api_version = 0;
108        EnumerateInstanceVersion(&api_version);
109
110        auto GetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(gipa(NULL, "vkGetInstanceProcAddr"));
111        ASSERT_EQ(GetInstanceProcAddr,
112                  reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr(NULL, "vkGetInstanceProcAddr")));
113
114        auto CreateInstance = reinterpret_cast<PFN_vkCreateInstance>(gipa(NULL, "vkCreateInstance"));
115        handle_assert_has_value(CreateInstance);
116    }
117    // Now create an instance and query the functions again - should work because the instance version is less than 1.2
118    for (int i = 0; i <= 2; i++) {
119        InstWrapper inst{env.vulkan_functions};
120        inst.create_info.api_version = VK_MAKE_API_VERSION(0, 1, i, 0);
121        inst.CheckCreate();
122
123        PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties =
124            inst.load("vkEnumerateInstanceExtensionProperties");
125        handle_assert_has_value(EnumerateInstanceExtensionProperties);
126        uint32_t ext_count = 0;
127        ASSERT_EQ(VK_SUCCESS, EnumerateInstanceExtensionProperties("", &ext_count, nullptr));
128
129        PFN_vkEnumerateInstanceLayerProperties EnumerateInstanceLayerProperties = inst.load("vkEnumerateInstanceLayerProperties");
130        handle_assert_has_value(EnumerateInstanceLayerProperties);
131        uint32_t layer_count = 0;
132        ASSERT_EQ(VK_SUCCESS, EnumerateInstanceLayerProperties(&layer_count, nullptr));
133
134        PFN_vkEnumerateInstanceVersion EnumerateInstanceVersion = inst.load("vkEnumerateInstanceVersion");
135        handle_assert_has_value(EnumerateInstanceVersion);
136        uint32_t api_version = 0;
137        EnumerateInstanceVersion(&api_version);
138
139        PFN_vkGetInstanceProcAddr GetInstanceProcAddr = inst.load("vkGetInstanceProcAddr");
140        handle_assert_has_value(GetInstanceProcAddr);
141        ASSERT_EQ(GetInstanceProcAddr,
142                  reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr(inst, "vkGetInstanceProcAddr")));
143
144        PFN_vkCreateInstance CreateInstance = inst.load("vkCreateInstance");
145        handle_assert_has_value(CreateInstance);
146    }
147    {
148        // Create a 1.3 instance - now everything should return NULL
149        InstWrapper inst{env.vulkan_functions};
150        inst.create_info.api_version = VK_MAKE_API_VERSION(0, 1, 3, 0);
151        inst.CheckCreate();
152
153        PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties =
154            inst.load("vkEnumerateInstanceExtensionProperties");
155        handle_assert_null(EnumerateInstanceExtensionProperties);
156
157        PFN_vkEnumerateInstanceLayerProperties EnumerateInstanceLayerProperties = inst.load("vkEnumerateInstanceLayerProperties");
158        handle_assert_null(EnumerateInstanceLayerProperties);
159
160        PFN_vkEnumerateInstanceVersion EnumerateInstanceVersion = inst.load("vkEnumerateInstanceVersion");
161        handle_assert_null(EnumerateInstanceVersion);
162
163        PFN_vkCreateInstance CreateInstance = inst.load("vkCreateInstance");
164        handle_assert_null(CreateInstance);
165
166        PFN_vkGetInstanceProcAddr GetInstanceProcAddr = inst.load("vkGetInstanceProcAddr");
167        handle_assert_equal(env.vulkan_functions.vkGetInstanceProcAddr, GetInstanceProcAddr);
168        ASSERT_EQ(GetInstanceProcAddr,
169                  reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr(inst, "vkGetInstanceProcAddr")));
170        ASSERT_EQ(GetInstanceProcAddr,
171                  reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr(NULL, "vkGetInstanceProcAddr")));
172        // get a non pre-instance function pointer
173        PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices = inst.load("vkEnumeratePhysicalDevices");
174        handle_assert_has_value(EnumeratePhysicalDevices);
175
176        EnumeratePhysicalDevices = reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(gipa(NULL, "vkEnumeratePhysicalDevices"));
177        handle_assert_null(EnumeratePhysicalDevices);
178    }
179}
180
181TEST(GetProcAddr, Verify10FunctionsFailToLoadWithSingleDriver) {
182    FrameworkEnvironment env{};
183    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({}).set_can_query_GetPhysicalDeviceFuncs(false);
184
185    InstWrapper inst{env.vulkan_functions};
186    inst.CheckCreate(VK_ERROR_INCOMPATIBLE_DRIVER);
187}
188
189TEST(GetProcAddr, Verify10FunctionsLoadWithMultipleDrivers) {
190    FrameworkEnvironment env{};
191    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
192    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({}).set_can_query_GetPhysicalDeviceFuncs(false);
193
194    InstWrapper inst{env.vulkan_functions};
195    inst.CheckCreate();
196
197    inst.GetPhysDevs(1);
198}
199
200// Swapchain functions which require a terminator in all cases have situations where the driver may have a
201// NULL function pointer but the loader shouldn't abort() if that is the case. Rather, it should log a message
202// and return VK_SUCCESS to maintain previous behavior.
203TEST(GetDeviceProcAddr, SwapchainFuncsWithTerminator) {
204    FrameworkEnvironment env{};
205    auto& driver =
206        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).setup_WSI().add_physical_device("physical_device_0");
207
208    InstWrapper inst(env.vulkan_functions);
209    inst.create_info.add_extension("VK_EXT_debug_utils");
210    inst.create_info.setup_WSI();
211    ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
212
213    VkSurfaceKHR surface{};
214    ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface));
215
216    DebugUtilsWrapper log{inst};
217    ASSERT_EQ(VK_SUCCESS, CreateDebugUtilsMessenger(log));
218    auto phys_dev = inst.GetPhysDev();
219    {
220        DeviceWrapper dev{inst};
221        ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
222        DeviceFunctions dev_funcs{env.vulkan_functions, dev};
223
224        PFN_vkCreateSwapchainKHR CreateSwapchainKHR = dev.load("vkCreateSwapchainKHR");
225        PFN_vkCreateSwapchainKHR inst_CreateSwapchainKHR = inst.load("vkCreateSwapchainKHR");
226        PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR =
227            dev.load("vkGetDeviceGroupSurfacePresentModesKHR");
228        PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR = dev.load("vkCreateSharedSwapchainsKHR");
229        ASSERT_FALSE(CreateSwapchainKHR);
230        ASSERT_TRUE(inst_CreateSwapchainKHR);
231        ASSERT_FALSE(GetDeviceGroupSurfacePresentModesKHR);
232        ASSERT_FALSE(CreateSharedSwapchainsKHR);
233
234        VkSwapchainCreateInfoKHR info{};
235        info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
236        info.surface = surface;
237
238        VkSwapchainKHR swapchain{};
239        if (CreateSwapchainKHR) CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain);
240        ASSERT_FALSE(
241            log.find("vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
242                     "extension enabled?"));
243        log.logger.clear();
244        if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
245        // try to call the vkCreateSwapchainKHR acquired from the instance - this *should* abort due to not enabling the extension
246        if (inst_CreateSwapchainKHR) {
247            ASSERT_DEATH(inst_CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain),
248                         "vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
249                         "extension enabled?");
250        }
251        log.logger.clear();
252        if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
253
254        VkDeviceGroupPresentModeFlagsKHR modes{};
255        if (GetDeviceGroupSurfacePresentModesKHR) GetDeviceGroupSurfacePresentModesKHR(dev.dev, surface, &modes);
256
257        if (CreateSharedSwapchainsKHR) CreateSharedSwapchainsKHR(dev.dev, 1, &info, nullptr, &swapchain);
258    }
259    driver.physical_devices.at(0).add_extensions({"VK_KHR_swapchain", "VK_KHR_display_swapchain", "VK_EXT_debug_marker"});
260    {
261        DeviceWrapper dev{inst};
262        dev.create_info.add_extensions({"VK_KHR_swapchain", "VK_KHR_display_swapchain", "VK_EXT_debug_marker"});
263        ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
264        DeviceFunctions dev_funcs{env.vulkan_functions, dev};
265
266        PFN_vkCreateSwapchainKHR CreateSwapchainKHR = dev.load("vkCreateSwapchainKHR");
267        PFN_vkCreateSwapchainKHR inst_CreateSwapchainKHR = inst.load("vkCreateSwapchainKHR");
268        PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR =
269            dev.load("vkGetDeviceGroupSurfacePresentModesKHR");
270        PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR = dev.load("vkCreateSharedSwapchainsKHR");
271        ASSERT_TRUE(CreateSwapchainKHR);
272        ASSERT_TRUE(inst_CreateSwapchainKHR);
273        ASSERT_TRUE(GetDeviceGroupSurfacePresentModesKHR);
274        ASSERT_TRUE(CreateSharedSwapchainsKHR);
275
276        VkSwapchainCreateInfoKHR info{};
277        info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
278        info.surface = surface;
279
280        VkSwapchainKHR swapchain{};
281        if (CreateSwapchainKHR) CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain);
282        ASSERT_FALSE(
283            log.find("vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
284                     "extension enabled?"));
285        log.logger.clear();
286        if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
287        if (inst_CreateSwapchainKHR) inst_CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain);
288        ASSERT_FALSE(
289            log.find("vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
290                     "extension enabled?"));
291        log.logger.clear();
292        if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
293
294        VkDeviceGroupPresentModeFlagsKHR modes{};
295        if (GetDeviceGroupSurfacePresentModesKHR) GetDeviceGroupSurfacePresentModesKHR(dev.dev, surface, &modes);
296
297        if (CreateSharedSwapchainsKHR) CreateSharedSwapchainsKHR(dev.dev, 1, &info, nullptr, &swapchain);
298    }
299    env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr);
300}
301
302// Verify that the various ways to get vkGetDeviceProcAddr return the same value
303TEST(GetProcAddr, PreserveLayerGettingVkCreateDeviceWithNullInstance) {
304    FrameworkEnvironment env{};
305    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device("physical_device_0");
306
307    env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
308                                                                          .set_name("VK_LAYER_technically_buggy_layer")
309                                                                          .set_description("actually_layer_1")
310                                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
311                                                                          .set_disable_environment("if_you_can")),
312                                            "buggy_layer_1.json"));
313    env.get_test_layer().set_buggy_query_of_vkCreateDevice(true);
314    InstWrapper inst{env.vulkan_functions};
315    inst.create_info.set_api_version(VK_API_VERSION_1_1);
316    inst.CheckCreate();
317    VkPhysicalDevice phys_dev = inst.GetPhysDev();
318
319    DeviceWrapper dev{inst};
320    dev.CheckCreate(phys_dev);
321}
322
323// The following tests - AppQueries11FunctionsWhileOnlyEnabling10, AppQueries12FunctionsWhileOnlyEnabling11, and
324// AppQueries13FunctionsWhileOnlyEnabling12 - check that vkGetDeviceProcAddr only returning functions from core versions up to
325// the apiVersion declared in VkApplicationInfo. Function querying should succeed if VK_KHR_maintenance_5 is not enabled, and they
326// should return zero when that extension is enabled.
327
328TEST(GetDeviceProcAddr, AppQueries11FunctionsWhileOnlyEnabling10) {
329    FrameworkEnvironment env{};
330    auto& driver =
331        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_1))
332            .set_icd_api_version(VK_API_VERSION_1_1)
333            .add_physical_device(
334                PhysicalDevice{}.set_api_version(VK_API_VERSION_1_1).add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME).finish());
335
336    std::vector<const char*> functions = {"vkGetDeviceQueue2", "vkCmdDispatchBase", "vkCreateDescriptorUpdateTemplate"};
337    for (const auto& f : functions) {
338        driver.physical_devices.back().add_device_function(VulkanFunction{f, [] {}});
339    }
340    {  // doesn't enable the feature or extension
341        InstWrapper inst{env.vulkan_functions};
342        inst.create_info.set_api_version(1, 0, 0);
343        inst.CheckCreate();
344
345        DeviceWrapper dev{inst};
346        dev.CheckCreate(inst.GetPhysDev());
347        for (const auto& f : functions) {
348            ASSERT_NE(nullptr, dev->vkGetDeviceProcAddr(dev.dev, f));
349        }
350    }
351    {  // doesn't enable the feature
352        InstWrapper inst{env.vulkan_functions};
353        inst.create_info.set_api_version(1, 0, 0);
354        inst.CheckCreate();
355
356        DeviceWrapper dev{inst};
357        dev.create_info.add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
358        dev.CheckCreate(inst.GetPhysDev());
359        for (const auto& f : functions) {
360            ASSERT_NE(nullptr, dev->vkGetDeviceProcAddr(dev.dev, f));
361        }
362    }
363    {  // enables the feature and extension
364        InstWrapper inst{env.vulkan_functions};
365        inst.create_info.set_api_version(1, 0, 0);
366        inst.CheckCreate();
367
368        VkPhysicalDeviceMaintenance5FeaturesKHR features{};
369        features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR;
370        features.maintenance5 = VK_TRUE;
371
372        DeviceWrapper dev{inst};
373        dev.create_info.add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
374        dev.create_info.dev.pNext = &features;
375        dev.CheckCreate(inst.GetPhysDev());
376        for (const auto& f : functions) {
377            ASSERT_EQ(nullptr, dev->vkGetDeviceProcAddr(dev.dev, f));
378        }
379    }
380}
381
382TEST(GetDeviceProcAddr, AppQueries12FunctionsWhileOnlyEnabling11) {
383    FrameworkEnvironment env{};
384    auto& driver =
385        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_2))
386            .set_icd_api_version(VK_API_VERSION_1_2)
387            .add_physical_device(
388                PhysicalDevice{}.set_api_version(VK_API_VERSION_1_2).add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME).finish());
389    std::vector<const char*> functions = {"vkCmdDrawIndirectCount", "vkCmdNextSubpass2", "vkGetBufferDeviceAddress",
390                                          "vkGetDeviceMemoryOpaqueCaptureAddress"};
391    for (const auto& f : functions) {
392        driver.physical_devices.back().add_device_function(VulkanFunction{f, [] {}});
393    }
394    {  // doesn't enable the feature or extension
395        InstWrapper inst{env.vulkan_functions};
396        inst.create_info.set_api_version(1, 1, 0);
397        inst.CheckCreate();
398
399        DeviceWrapper dev{inst};
400        dev.CheckCreate(inst.GetPhysDev());
401
402        for (const auto& f : functions) {
403            ASSERT_NE(nullptr, dev->vkGetDeviceProcAddr(dev.dev, f));
404        }
405    }
406    {  // doesn't enable the feature
407        InstWrapper inst{env.vulkan_functions};
408        inst.create_info.set_api_version(1, 1, 0);
409        inst.CheckCreate();
410
411        DeviceWrapper dev{inst};
412        dev.create_info.add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
413        dev.CheckCreate(inst.GetPhysDev());
414
415        for (const auto& f : functions) {
416            ASSERT_NE(nullptr, dev->vkGetDeviceProcAddr(dev.dev, f));
417        }
418    }
419    {  // enables the feature and extension
420        InstWrapper inst{env.vulkan_functions};
421        inst.create_info.set_api_version(1, 1, 0);
422        inst.CheckCreate();
423
424        VkPhysicalDeviceMaintenance5FeaturesKHR features{};
425        features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR;
426        features.maintenance5 = VK_TRUE;
427
428        DeviceWrapper dev{inst};
429        dev.create_info.add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
430        dev.create_info.dev.pNext = &features;
431        dev.CheckCreate(inst.GetPhysDev());
432
433        for (const auto& f : functions) {
434            ASSERT_EQ(nullptr, dev->vkGetDeviceProcAddr(dev.dev, f));
435        }
436    }
437}
438
439TEST(GetDeviceProcAddr, AppQueries13FunctionsWhileOnlyEnabling12) {
440    FrameworkEnvironment env{};
441    auto& driver =
442        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_3))
443            .set_icd_api_version(VK_API_VERSION_1_3)
444            .add_physical_device(
445                PhysicalDevice{}.set_api_version(VK_API_VERSION_1_3).add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME).finish());
446    std::vector<const char*> functions = {"vkCreatePrivateDataSlot", "vkGetDeviceBufferMemoryRequirements", "vkCmdWaitEvents2",
447                                          "vkGetDeviceImageSparseMemoryRequirements"};
448
449    for (const auto& f : functions) {
450        driver.physical_devices.back().add_device_function(VulkanFunction{f, [] {}});
451    }
452    {  // doesn't enable the feature or extension
453        InstWrapper inst{env.vulkan_functions};
454        inst.create_info.set_api_version(1, 2, 0);
455        inst.CheckCreate();
456
457        DeviceWrapper dev{inst};
458        dev.CheckCreate(inst.GetPhysDev());
459
460        for (const auto& f : functions) {
461            ASSERT_NE(nullptr, dev->vkGetDeviceProcAddr(dev.dev, f));
462        }
463    }
464    {  // doesn't enable the feature
465        InstWrapper inst{env.vulkan_functions};
466        inst.create_info.set_api_version(1, 2, 0);
467        inst.CheckCreate();
468
469        DeviceWrapper dev{inst};
470        dev.create_info.add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
471        dev.CheckCreate(inst.GetPhysDev());
472
473        for (const auto& f : functions) {
474            ASSERT_NE(nullptr, dev->vkGetDeviceProcAddr(dev.dev, f));
475        }
476    }
477    {  // enables the feature and extension
478        InstWrapper inst{env.vulkan_functions};
479        inst.create_info.set_api_version(1, 2, 0);
480        inst.CheckCreate();
481
482        VkPhysicalDeviceMaintenance5FeaturesKHR features{};
483        features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR;
484        features.maintenance5 = VK_TRUE;
485
486        DeviceWrapper dev{inst};
487        dev.create_info.add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
488        dev.create_info.dev.pNext = &features;
489        dev.CheckCreate(inst.GetPhysDev());
490
491        for (const auto& f : functions) {
492            ASSERT_EQ(nullptr, dev->vkGetDeviceProcAddr(dev.dev, f));
493        }
494    }
495}
496