Fix VkNonDispatchableHandle alignment on Linux x86
There alignof(uint64_t) is 8 but it is aligned to 4 inside structures.
Change-Id: Ia94e9e5c962e9f5898a8f39977b83a9e10cbf454
diff --git a/src/common/vulkan_platform.h b/src/common/vulkan_platform.h
index 445fae6..81f0406 100644
--- a/src/common/vulkan_platform.h
+++ b/src/common/vulkan_platform.h
@@ -32,21 +32,41 @@
// redefined to be nullptr). This keeps the type-safety of having the handles be different types
// (like vulkan.h on 64 bit) but makes sure the types are different on 32 bit architectures.
-// Force the handle type to have the same alignment as what would have been the Vulkan
-// non-dispatchable handle type.
#if defined(DAWN_PLATFORM_64_BIT)
-// In 64 bit handles are pointers to some structure, we just declare one inline here.
-using NativeVulkanHandleType = struct VkSomeHandle*;
+# define DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) \
+ using object##Native = struct object##_T*;
#elif defined(DAWN_PLATFORM_32_BIT)
-using NativeVulkanHandleType = uint64_t;
-# define ALIGNAS_VULKAN_HANDLE alignas(alignof(uint64_t))
+# define DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) using object##Native = uint64_t;
#else
# error "Unsupported platform"
#endif
+// Define a dummy Vulkan handle for use before we include vulkan.h
+DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(VkSomeHandle)
+
+// Find out the alignment of native handles. Logically we would use alignof(VkSomeHandleNative) so
+// why bother with the wrapper struct? It turns out that on Linux Intel x86 alignof(uint64_t) is 8
+// but alignof(struct{uint64_t a;}) is 4. This is because this Intel ABI doesn't say anything about
+// double-word alignment so for historical reasons compilers violated the standard and use an
+// alignment of 4 for uint64_t (and double) inside structures.
+// See https://stackoverflow.com/questions/44877185
+// One way to get the alignment inside structures of a type is to look at the alignment of it
+// wrapped in a structure. Hence VkSameHandleNativeWrappe
+
+template <typename T>
+struct WrapperStruct {
+ T member;
+};
+
+template <typename T>
+static constexpr size_t AlignOfInStruct = alignof(WrapperStruct<T>);
+
+static constexpr size_t kNativeVkHandleAlignment = AlignOfInStruct<VkSomeHandleNative>;
+static constexpr size_t kUint64Alignment = AlignOfInStruct<VkSomeHandleNative>;
+
// Simple handle types that supports "nullptr_t" as a 0 value.
template <typename Tag, typename HandleType>
-class alignas(alignof(NativeVulkanHandleType)) VkNonDispatchableHandle {
+class alignas(kNativeVkHandleAlignment) VkNonDispatchableHandle {
public:
// Default constructor and assigning of VK_NULL_HANDLE
VkNonDispatchableHandle() = default;
@@ -116,23 +136,14 @@
uint64_t mHandle = 0;
};
-#if defined(DAWN_PLATFORM_64_BIT)
-# define DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) \
- using object##Native = struct object##_T*;
-#elif defined(DAWN_PLATFORM_32_BIT)
-# define DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) using object##Native = uint64_t;
-#else
-# error "Unsupported platform"
-#endif
-
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \
struct VkTag##object; \
DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) \
using object = VkNonDispatchableHandle<VkTag##object, object##Native>; \
static_assert(sizeof(object) == sizeof(uint64_t), ""); \
- static_assert(alignof(object) == alignof(uint64_t), ""); \
+ static_assert(alignof(object) == kUint64Alignment, ""); \
static_assert(sizeof(object) == sizeof(object##Native), ""); \
- static_assert(alignof(object) == alignof(object##Native), "");
+ static_assert(alignof(object) == kNativeVkHandleAlignment, "");
# include <vulkan/vulkan.h>