Fix VkNonDispatchableHandle alignment on Linux x86

There alignof(uint64_t) is 8 but it is aligned to 4 inside structures.

Change-Id: Ia94e9e5c962e9f5898a8f39977b83a9e10cbf454
This commit is contained in:
Corentin Wallez 2018-09-03 17:48:12 +02:00 committed by Corentin Wallez
parent ca81bd3481
commit 98ca29b582
1 changed files with 29 additions and 18 deletions

View File

@ -32,21 +32,41 @@
// redefined to be nullptr). This keeps the type-safety of having the handles be different types // 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. // (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) #if defined(DAWN_PLATFORM_64_BIT)
// In 64 bit handles are pointers to some structure, we just declare one inline here. # define DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) \
using NativeVulkanHandleType = struct VkSomeHandle*; using object##Native = struct object##_T*;
#elif defined(DAWN_PLATFORM_32_BIT) #elif defined(DAWN_PLATFORM_32_BIT)
using NativeVulkanHandleType = uint64_t; # define DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) using object##Native = uint64_t;
# define ALIGNAS_VULKAN_HANDLE alignas(alignof(uint64_t))
#else #else
# error "Unsupported platform" # error "Unsupported platform"
#endif #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. // Simple handle types that supports "nullptr_t" as a 0 value.
template <typename Tag, typename HandleType> template <typename Tag, typename HandleType>
class alignas(alignof(NativeVulkanHandleType)) VkNonDispatchableHandle { class alignas(kNativeVkHandleAlignment) VkNonDispatchableHandle {
public: public:
// Default constructor and assigning of VK_NULL_HANDLE // Default constructor and assigning of VK_NULL_HANDLE
VkNonDispatchableHandle() = default; VkNonDispatchableHandle() = default;
@ -116,23 +136,14 @@ class alignas(alignof(NativeVulkanHandleType)) VkNonDispatchableHandle {
uint64_t mHandle = 0; 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) \ #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \
struct VkTag##object; \ struct VkTag##object; \
DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) \ DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) \
using object = VkNonDispatchableHandle<VkTag##object, object##Native>; \ using object = VkNonDispatchableHandle<VkTag##object, object##Native>; \
static_assert(sizeof(object) == sizeof(uint64_t), ""); \ 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(sizeof(object) == sizeof(object##Native), ""); \
static_assert(alignof(object) == alignof(object##Native), ""); static_assert(alignof(object) == kNativeVkHandleAlignment, "");
# include <vulkan/vulkan.h> # include <vulkan/vulkan.h>