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>