Skip to content

Commit 7205aa5

Browse files
tests: Compare proc-addr behavior, not identity, on arm64ec
On arm64ec, GetProcAddress for an exported function returns the export's Fast-Forward Sequence (x64-shaped) address, while the loader resolves its own name to the native arm64ec function body. These are distinct addresses but valid entry points for the same command, and the Vulkan spec does not require pointer identity between a platform export and a vkGet*ProcAddr result. GetProcAddr.VerifyGetInstanceProcAddr, VerifyGetDeviceProcAddr and GlobalFunctions asserted raw pointer equality, which fails on arm64ec. Under _M_ARM64EC, compare behavior instead - both pointers non-NULL, an unknown command resolves to NULL, and a known command resolves to the same pointer - and keep strict pointer equality on every other architecture.
1 parent 79f7250 commit 7205aa5

1 file changed

Lines changed: 41 additions & 5 deletions

File tree

tests/loader_get_proc_addr_tests.cpp

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,42 @@
2727

2828
#include "test_environment.h"
2929

30+
// On arm64ec GetProcAddress hands back an export's x64 fast-forward-sequence address while the loader
31+
// resolves its own name to the native arm64ec function. Same command, different addresses, and the
32+
// spec doesn't require them to match, so compare behavior on arm64ec instead of raw pointer identity.
33+
static void assert_gipa_equivalent(PFN_vkGetInstanceProcAddr from_loader, PFN_vkGetInstanceProcAddr from_query) {
34+
#if defined(_M_ARM64EC)
35+
ASSERT_NE(from_loader, nullptr);
36+
ASSERT_NE(from_query, nullptr);
37+
ASSERT_EQ(from_loader(nullptr, "vkThisCommandDoesNotExist"), nullptr);
38+
ASSERT_EQ(from_query(nullptr, "vkThisCommandDoesNotExist"), nullptr);
39+
PFN_vkVoidFunction create_from_loader = from_loader(nullptr, "vkCreateInstance");
40+
PFN_vkVoidFunction create_from_query = from_query(nullptr, "vkCreateInstance");
41+
ASSERT_NE(create_from_loader, nullptr);
42+
ASSERT_EQ(create_from_loader, create_from_query);
43+
#else
44+
ASSERT_EQ(from_loader, from_query);
45+
#endif
46+
}
47+
48+
static void assert_gdpa_equivalent(PFN_vkGetDeviceProcAddr from_loader, PFN_vkGetDeviceProcAddr from_query, VkDevice device) {
49+
#if defined(_M_ARM64EC)
50+
ASSERT_NE(from_loader, nullptr);
51+
ASSERT_NE(from_query, nullptr);
52+
if (device != VK_NULL_HANDLE) {
53+
ASSERT_EQ(from_loader(device, "vkThisCommandDoesNotExist"), nullptr);
54+
ASSERT_EQ(from_query(device, "vkThisCommandDoesNotExist"), nullptr);
55+
PFN_vkVoidFunction destroy_from_loader = from_loader(device, "vkDestroyDevice");
56+
PFN_vkVoidFunction destroy_from_query = from_query(device, "vkDestroyDevice");
57+
ASSERT_NE(destroy_from_loader, nullptr);
58+
ASSERT_EQ(destroy_from_loader, destroy_from_query);
59+
}
60+
#else
61+
(void)device;
62+
ASSERT_EQ(from_loader, from_query);
63+
#endif
64+
}
65+
3066
// Verify that the various ways to get vkGetInstanceProcAddr return the same value
3167
TEST(GetProcAddr, VerifyGetInstanceProcAddr) {
3268
FrameworkEnvironment env{};
@@ -41,7 +77,7 @@ TEST(GetProcAddr, VerifyGetInstanceProcAddr) {
4177
PFN_vkGetInstanceProcAddr gipa_loader = env.vulkan_functions.vkGetInstanceProcAddr;
4278
PFN_vkGetInstanceProcAddr gipa_queried = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
4379
env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkGetInstanceProcAddr"));
44-
ASSERT_EQ(gipa_loader, gipa_queried);
80+
assert_gipa_equivalent(gipa_loader, gipa_queried);
4581
}
4682

4783
{
@@ -54,7 +90,7 @@ TEST(GetProcAddr, VerifyGetInstanceProcAddr) {
5490
PFN_vkGetInstanceProcAddr gipa_loader = env.vulkan_functions.vkGetInstanceProcAddr;
5591
PFN_vkGetInstanceProcAddr gipa_queried = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
5692
env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkGetInstanceProcAddr"));
57-
ASSERT_EQ(gipa_loader, gipa_queried);
93+
assert_gipa_equivalent(gipa_loader, gipa_queried);
5894
}
5995
}
6096

@@ -72,13 +108,13 @@ TEST(GetProcAddr, VerifyGetDeviceProcAddr) {
72108
// that to what is returned by asking it what the various Vulkan get proc addr functions are.
73109
PFN_vkGetDeviceProcAddr gdpa_loader = env.vulkan_functions.vkGetDeviceProcAddr;
74110
PFN_vkGetDeviceProcAddr gdpa_inst_queried = inst.load("vkGetDeviceProcAddr");
75-
ASSERT_EQ(gdpa_loader, gdpa_inst_queried);
111+
assert_gdpa_equivalent(gdpa_loader, gdpa_inst_queried, VK_NULL_HANDLE);
76112

77113
DeviceWrapper dev{inst};
78114
dev.CheckCreate(phys_dev);
79115

80116
PFN_vkGetDeviceProcAddr gdpa_dev_queried = dev.load("vkGetDeviceProcAddr");
81-
ASSERT_EQ(gdpa_loader, gdpa_dev_queried);
117+
assert_gdpa_equivalent(gdpa_loader, gdpa_dev_queried, dev);
82118
}
83119

84120
// Load the global function pointers with and without a NULL vkInstance handle.
@@ -164,7 +200,7 @@ TEST(GetProcAddr, GlobalFunctions) {
164200
handle_assert_null(CreateInstance);
165201

166202
PFN_vkGetInstanceProcAddr GetInstanceProcAddr = inst.load("vkGetInstanceProcAddr");
167-
handle_assert_equal(env.vulkan_functions.vkGetInstanceProcAddr, GetInstanceProcAddr);
203+
assert_gipa_equivalent(env.vulkan_functions.vkGetInstanceProcAddr, GetInstanceProcAddr);
168204
ASSERT_EQ(GetInstanceProcAddr,
169205
reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr(inst, "vkGetInstanceProcAddr")));
170206
ASSERT_EQ(GetInstanceProcAddr,

0 commit comments

Comments
 (0)