From 98ca29b582a0f33081770499773f6f2a927fd985 Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Mon, 3 Sep 2018 17:48:12 +0200 Subject: [PATCH] Fix VkNonDispatchableHandle alignment on Linux x86 There alignof(uint64_t) is 8 but it is aligned to 4 inside structures. Change-Id: Ia94e9e5c962e9f5898a8f39977b83a9e10cbf454 --- src/common/vulkan_platform.h | 47 ++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/common/vulkan_platform.h b/src/common/vulkan_platform.h index 445fae60b4..81f0406bc5 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 +struct WrapperStruct { + T member; +}; + +template +static constexpr size_t AlignOfInStruct = alignof(WrapperStruct); + +static constexpr size_t kNativeVkHandleAlignment = AlignOfInStruct; +static constexpr size_t kUint64Alignment = AlignOfInStruct; + // Simple handle types that supports "nullptr_t" as a 0 value. template -class alignas(alignof(NativeVulkanHandleType)) VkNonDispatchableHandle { +class alignas(kNativeVkHandleAlignment) VkNonDispatchableHandle { public: // Default constructor and assigning of VK_NULL_HANDLE VkNonDispatchableHandle() = default; @@ -116,23 +136,14 @@ class alignas(alignof(NativeVulkanHandleType)) VkNonDispatchableHandle { 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; \ 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