В шапке Вулкана vulkan.h
есть структура, определенная как
typedef struct VkSwapchainCreateInfoKHR {
VkStructureType sType;
const void* pNext;
VkSwapchainCreateFlagsKHR flags;
VkSurfaceKHR surface;
uint32_t minImageCount;
VkFormat imageFormat;
VkColorSpaceKHR imageColorSpace;
VkExtent2D imageExtent;
uint32_t imageArrayLayers;
VkImageUsageFlags imageUsage;
VkSharingMode imageSharingMode;
uint32_t queueFamilyIndexCount;
const uint32_t* pQueueFamilyIndices;
VkSurfaceTransformFlagBitsKHR preTransform;
VkCompositeAlphaFlagBitsKHR compositeAlpha;
VkPresentModeKHR presentMode;
VkBool32 clipped;
VkSwapchainKHR oldSwapchain;
} VkSwapchainCreateInfoKHR;
Я использовал следующий код, чтобы увидеть выравнивание каждого поля (Visual Studio 2015)
std::cout <<
"sType: " << offsetof(VkSwapchainCreateInfoKHR, sType) << std::endl <<
"pNext: " << offsetof(VkSwapchainCreateInfoKHR, pNext) << std::endl <<
"flags: " << offsetof(VkSwapchainCreateInfoKHR, flags) << std::endl <<
"surface: " << offsetof(VkSwapchainCreateInfoKHR, surface) << std::endl <<
"minImageCount: " << offsetof(VkSwapchainCreateInfoKHR, minImageCount) << std::endl <<
"imageFormat: " << offsetof(VkSwapchainCreateInfoKHR, imageFormat) << std::endl <<
"imageColorSpace: " << offsetof(VkSwapchainCreateInfoKHR, imageColorSpace) << std::endl <<
"imageExtent: " << offsetof(VkSwapchainCreateInfoKHR, imageExtent) << std::endl <<
"imageArrayLayers: " << offsetof(VkSwapchainCreateInfoKHR, imageArrayLayers) << std::endl <<
"imageUsage: " << offsetof(VkSwapchainCreateInfoKHR, imageUsage) << std::endl <<
"imageSharingMode: " << offsetof(VkSwapchainCreateInfoKHR, imageSharingMode) << std::endl <<
"queueFamilyIndexCount: " << offsetof(VkSwapchainCreateInfoKHR, queueFamilyIndexCount) << std::endl <<
"pQueueFamilyIndices: " << offsetof(VkSwapchainCreateInfoKHR, pQueueFamilyIndices) << std::endl <<
"preTransform: " << offsetof(VkSwapchainCreateInfoKHR, preTransform) << std::endl <<
"compositeAlpha: " << offsetof(VkSwapchainCreateInfoKHR, compositeAlpha) << std::endl <<
"presentMode: " << offsetof(VkSwapchainCreateInfoKHR, presentMode) << std::endl <<
"clipped: " << offsetof(VkSwapchainCreateInfoKHR, clipped) << std::endl <<
"oldSwapchain: " << offsetof(VkSwapchainCreateInfoKHR, oldSwapchain) << std::endl <<
std::endl;
И получил эти результаты
sType: 0
pNext: 8
flags: 16
surface: 24
minImageCount: 32
imageFormat: 36
imageColorSpace: 40
imageExtent: 44
imageArrayLayers: 52
imageUsageFlags: 56
imageSharingMode: 60
queueFamilyIndexCount: 64
pQueueFamilyIndices: 72
preTransform: 80
compositeAlpha: 84
presentMode: 88
clipped: 92
oldSwapchain: 96
Между полями flags
а также surface
есть 8-байтный пробел, хотя flags
имеет базовый тип uint32_t
, То же самое относится и к полям queueFamilyIndexCount
а также pQueueFamilyIndices
, Почему flags
а также queueFamilyIndexCount
занимают 8 байтов, когда они имеют ширину всего 4 байта, и каждое другое поле типа uint32_t
занимает всего 4 байта? Есть ли что-то особенное в требованиях к выравниванию памяти в этих смещениях?
VkSurfaceKHR
это не отправляемая ручка. Который, по определениям Вулкана, является 64-битным целым числом. И поэтому он должен иметь 8-байтовое выравнивание.
Когда структуры размечаются, компилятор гарантирует, что каждый элемент получит выравнивание, которое требует тип. Если surface
пришел сразу после flags
, он не будет иметь 8-байтовое выравнивание. Таким образом, компилятор вставляет 4 байта заполнения между ними.
Все типы имеют размер sizeof(T)
и требование выравнивания alignof(T)
, Его экземпляры всегда должны быть размещены в памяти по адресам, кратным alignof(T)
,
В структуре компилятор автоматически вставляет набивка между элементами, так что это требование выполняется для всех его элементов относительно начального адреса структуры (то есть для offsetof
ценности). Это пустое пространство между последующими элементами структуры.
Это также устанавливает alignof
всей структуры, так что все ее элементы будут правильно выровнены в памяти. Например, на типичной 64-битной платформе:
struct A {
char c; // sizeof(char) == 1; alignof(char) == 1
int* ptr; // sizeof(char) == 8; alignof(char) == 8
}
Указатели имеют размер 8 байт (64 бита), а также требование выравнивания 8 байт. В этой структуре будет 7 байтов заполнения c
а также ptr
такой, что offsetof(A, c) == 0
а также offsetof(A, ptr) == 8
, А также alignof(A) == 8
, Всякий раз, когда экземпляр A a
создается (в стеке или в куче), &a % 8 == 0
, так что &(a.ptr) % 8 == 0
,
Это сделано потому, что некоторые инструкции ЦП (например, векторные инструкции SIMD) требуют, чтобы их операнды были выровнены по границам слова, то есть кратны 8 (или 4 для 32-битных) в памяти. Без правильного выравнивания эти инструкции не могут быть использованы напрямую, и программа станет медленнее.
В этом примере VkSurfaceKHR
а также pQueueFamilyIndices
указатели с alignof == 8
,