Skip to content

Commit aa8fde2

Browse files
authored
Fix alignedVkSize() usages on possibly non-PoT values (#1294)
I chose to unify different alignment functions into one template which can be used on any values/types universally. This fixes a bug on one platform in which VkPhysicalDeviceProperties2::bufferDescriptorSize was reported to be 24 (0x18) which didn't work properly.
1 parent 41a4410 commit aa8fde2

6 files changed

Lines changed: 41 additions & 54 deletions

File tree

‎base/VulkanTools.cpp‎

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -474,22 +474,5 @@ namespace vks
474474
std::ifstream f(filename.c_str());
475475
return !f.fail();
476476
}
477-
478-
uint32_t alignedSize(uint32_t value, uint32_t alignment)
479-
{
480-
return (value + alignment - 1) & ~(alignment - 1);
481-
}
482-
483-
size_t alignedSize(size_t value, size_t alignment)
484-
{
485-
return (value + alignment - 1) & ~(alignment - 1);
486-
}
487-
488-
489-
VkDeviceSize alignedVkSize(VkDeviceSize value, VkDeviceSize alignment)
490-
{
491-
return (value + alignment - 1) & ~(alignment - 1);
492-
}
493-
494477
}
495478
}

‎base/VulkanTools.h‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,11 @@ VkShaderModule loadShader(const char *fileName, VkDevice device);
152152
/** @brief Checks if a file exists */
153153
bool fileExists(const std::string &filename);
154154

155-
uint32_t alignedSize(uint32_t value, uint32_t alignment);
156-
VkDeviceSize alignedVkSize(VkDeviceSize value, VkDeviceSize alignment);
155+
// Return `value` aligned to `alignment`
156+
template<typename T>
157+
constexpr T alignedSize(T value, T alignment)
158+
{
159+
return (((value + (alignment - 1)) / alignment) * alignment);
160+
}
157161
}
158162
}

‎examples/descriptorbuffer/descriptorbuffer.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,8 @@ class VulkanExample : public VulkanExampleBase
213213
vkGetDescriptorSetLayoutBindingOffsetEXT(device, combinedImageDescriptor.setLayout, 0, &combinedImageDescriptor.layoutOffset);
214214

215215
// In order to copy resource descriptors to the correct place, we need to calculate aligned sizes
216-
uniformDescriptor.layoutSize = vks::tools::alignedVkSize(uniformDescriptor.layoutSize, descriptorBufferProperties.descriptorBufferOffsetAlignment);
217-
combinedImageDescriptor.layoutSize = vks::tools::alignedVkSize(combinedImageDescriptor.layoutSize, descriptorBufferProperties.descriptorBufferOffsetAlignment);
216+
uniformDescriptor.layoutSize = vks::tools::alignedSize(uniformDescriptor.layoutSize, descriptorBufferProperties.descriptorBufferOffsetAlignment);
217+
combinedImageDescriptor.layoutSize = vks::tools::alignedSize(combinedImageDescriptor.layoutSize, descriptorBufferProperties.descriptorBufferOffsetAlignment);
218218

219219
// This buffer will contain resource descriptors for all the uniform buffers of a single frame (global matrices and cubes)
220220
uint32_t bufferDescriptorSize = (static_cast<uint32_t>(cubes.size()) + 1) * uniformDescriptor.layoutSize;

‎examples/descriptorheap/descriptorheap.cpp‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,10 @@ class VulkanExample : public VulkanExampleBase
152152

153153
// Sampler heap
154154
// We need to calculate some aligned offsets, heaps and strides to make sure we properly accress the descriptors
155-
samplerDescriptorSize = vks::tools::alignedVkSize(descriptorHeapProperties.samplerDescriptorSize, descriptorHeapProperties.samplerDescriptorAlignment);
155+
samplerDescriptorSize = vks::tools::alignedSize(descriptorHeapProperties.samplerDescriptorSize, descriptorHeapProperties.samplerDescriptorAlignment);
156156

157157
// Size calculations for the heap also need to accomodate for the reserved range, used by the driver for internal bookkeeping
158-
const VkDeviceSize heapSizeSamplers = vks::tools::alignedVkSize(samplerDescriptorSize * 2 + descriptorHeapProperties.minSamplerHeapReservedRange, descriptorHeapProperties.samplerHeapAlignment);
158+
const VkDeviceSize heapSizeSamplers = vks::tools::alignedSize(samplerDescriptorSize * 2 + descriptorHeapProperties.minSamplerHeapReservedRange, descriptorHeapProperties.samplerHeapAlignment);
159159
VK_CHECK_RESULT(vulkanDevice->createBuffer(
160160
VK_BUFFER_USAGE_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
161161
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
@@ -203,13 +203,13 @@ class VulkanExample : public VulkanExampleBase
203203
VK_CHECK_RESULT(vkWriteSamplerDescriptorsEXT(device, static_cast<uint32_t>(samplerCreateInfos.size()), samplerCreateInfos.data(), hostAddressRangesSamplers.data()));
204204

205205
// Resource heap (buffers and images)
206-
bufferDescriptorSize = vks::tools::alignedVkSize(descriptorHeapProperties.bufferDescriptorSize, descriptorHeapProperties.bufferDescriptorAlignment);
207-
imageDescriptorSize = vks::tools::alignedVkSize(descriptorHeapProperties.imageDescriptorSize, descriptorHeapProperties.imageDescriptorAlignment);
206+
bufferDescriptorSize = vks::tools::alignedSize(descriptorHeapProperties.bufferDescriptorSize, descriptorHeapProperties.bufferDescriptorAlignment);
207+
imageDescriptorSize = vks::tools::alignedSize(descriptorHeapProperties.imageDescriptorSize, descriptorHeapProperties.imageDescriptorAlignment);
208208
// Images are stored after the last buffer (aligned)
209-
imageHeapOffset = vks::tools::alignedVkSize(2 * bufferDescriptorSize, imageDescriptorSize);
209+
imageHeapOffset = vks::tools::alignedSize(2 * bufferDescriptorSize, imageDescriptorSize);
210210

211211
// Size calculations for the heap also need to accomodate for the reserved range, used by the driver for internal bookkeeping
212-
const VkDeviceSize heapSizeResources = vks::tools::alignedVkSize(imageHeapOffset + imageDescriptorSize * 2 + descriptorHeapProperties.minResourceHeapReservedRange, descriptorHeapProperties.resourceHeapAlignment);
212+
const VkDeviceSize heapSizeResources = vks::tools::alignedSize(imageHeapOffset + imageDescriptorSize * 2 + descriptorHeapProperties.minResourceHeapReservedRange, descriptorHeapProperties.resourceHeapAlignment);
213213
VK_CHECK_RESULT(vulkanDevice->createBuffer(
214214
VK_BUFFER_USAGE_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
215215
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,

‎examples/descriptorheapuntyped/descriptorheapuntyped.cpp‎

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/*
22
* Vulkan Example - Using untyped descriptor heaps via VK_EXT_descriptor_heap
3-
*
3+
*
44
* Descriptor heaps fundamentally rework how shader resources are bound. Descriptors are simply stored in buffers (heaps).
5-
*
5+
*
66
* Note: This sample also uses uniform buffers and buffer device address to pass global data
77
*
88
* Copyright (C) 2026 by Sascha Willems - www.saschawillems.de
@@ -40,7 +40,7 @@ class VulkanExample : public VulkanExampleBase
4040
vkglTF::Model model;
4141

4242
VkPipeline pipeline{ nullptr };
43-
43+
4444
VkPhysicalDeviceVulkan12Features enabledDeviceVulkan12Features{};
4545
VkPhysicalDeviceDescriptorHeapFeaturesEXT enabledDeviceDescriptorHeapFeaturesEXT{};
4646
VkPhysicalDeviceSynchronization2Features enabledSynchronization2Features{};
@@ -169,10 +169,10 @@ class VulkanExample : public VulkanExampleBase
169169

170170
// Sampler heap
171171
// We need to calculate some aligned offsets, heaps and strides to make sure we properly accress the descriptors
172-
samplerDescriptorSize = vks::tools::alignedVkSize(descriptorHeapProperties.samplerDescriptorSize, descriptorHeapProperties.samplerDescriptorAlignment);
172+
samplerDescriptorSize = vks::tools::alignedSize(descriptorHeapProperties.samplerDescriptorSize, descriptorHeapProperties.samplerDescriptorAlignment);
173173

174174
// Size calculations for the heap also need to accomodate for the reserved range, used by the driver for internal bookkeeping
175-
const VkDeviceSize heapSizeSamplers = vks::tools::alignedVkSize(samplerDescriptorSize * 2 + descriptorHeapProperties.minSamplerHeapReservedRange, descriptorHeapProperties.samplerHeapAlignment);
175+
const VkDeviceSize heapSizeSamplers = vks::tools::alignedSize(samplerDescriptorSize * 2 + descriptorHeapProperties.minSamplerHeapReservedRange, descriptorHeapProperties.samplerHeapAlignment);
176176
VK_CHECK_RESULT(vulkanDevice->createBuffer(
177177
VK_BUFFER_USAGE_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
178178
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
@@ -220,13 +220,13 @@ class VulkanExample : public VulkanExampleBase
220220
VK_CHECK_RESULT(vkWriteSamplerDescriptorsEXT(device, static_cast<uint32_t>(samplerCreateInfos.size()), samplerCreateInfos.data(), hostAddressRangesSamplers.data()));
221221

222222
// Resource heap (buffers and images)
223-
bufferDescriptorSize = vks::tools::alignedVkSize(descriptorHeapProperties.bufferDescriptorSize, descriptorHeapProperties.bufferDescriptorAlignment);
224-
imageDescriptorSize = vks::tools::alignedVkSize(descriptorHeapProperties.imageDescriptorSize, descriptorHeapProperties.imageDescriptorAlignment);
223+
bufferDescriptorSize = vks::tools::alignedSize(descriptorHeapProperties.bufferDescriptorSize, descriptorHeapProperties.bufferDescriptorAlignment);
224+
imageDescriptorSize = vks::tools::alignedSize(descriptorHeapProperties.imageDescriptorSize, descriptorHeapProperties.imageDescriptorAlignment);
225225
// Images are stored after the last buffer (aligned)
226-
imageHeapOffset = vks::tools::alignedVkSize(2 * bufferDescriptorSize, imageDescriptorSize);
226+
imageHeapOffset = vks::tools::alignedSize(2 * bufferDescriptorSize, imageDescriptorSize);
227227

228228
// Size calculations for the heap also need to accomodate for the reserved range, used by the driver for internal bookkeeping
229-
const VkDeviceSize heapSizeResources = vks::tools::alignedVkSize(imageHeapOffset + imageDescriptorSize * 2 + descriptorHeapProperties.minResourceHeapReservedRange, descriptorHeapProperties.resourceHeapAlignment);
229+
const VkDeviceSize heapSizeResources = vks::tools::alignedSize(imageHeapOffset + imageDescriptorSize * 2 + descriptorHeapProperties.minResourceHeapReservedRange, descriptorHeapProperties.resourceHeapAlignment);
230230
VK_CHECK_RESULT(vulkanDevice->createBuffer(
231231
VK_BUFFER_USAGE_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
232232
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
@@ -237,7 +237,7 @@ class VulkanExample : public VulkanExampleBase
237237

238238
std::vector<VkHostAddressRangeEXT> hostAddressRangesResources{};
239239
std::vector<VkResourceDescriptorInfoEXT> resourceDescriptorInfos{};
240-
240+
241241
// Buffer data
242242
std::array<VkDeviceAddressRangeEXT, 2> deviceAddressRangesModelData{};
243243

@@ -340,7 +340,7 @@ class VulkanExample : public VulkanExampleBase
340340
.depthAttachmentFormat = depthFormat,
341341
.stencilAttachmentFormat = depthFormat
342342
};
343-
343+
344344
// With descriptor heaps we no longer need a pipeline layout
345345
// This struct must be chained into pipeline creation to enable the use of heaps (allowing us to leave pipelineLayout empty)
346346
VkPipelineCreateFlags2CreateInfo pipelineCreateFlags2CI{
@@ -362,7 +362,7 @@ class VulkanExample : public VulkanExampleBase
362362
}
363363

364364
void updateUniformBuffers()
365-
{
365+
{
366366
uniformData.mvp = camera.matrices.perspective* camera.matrices.view;
367367
uniformData.samplerIndex = selectedSampler;
368368
memcpy(uniformBuffers[currentBuffer].mapped, &uniformData, sizeof(UniformData));
@@ -414,7 +414,7 @@ class VulkanExample : public VulkanExampleBase
414414
.reservedRangeSize = descriptorHeapProperties.minResourceHeapReservedRange,
415415
};
416416
vkCmdBindResourceHeapEXT(cmdBuffer, &bindHeapInfoRes);
417-
417+
418418
// Bind the heap containing samplers
419419
VkBindHeapInfoEXT bindHeapInfoSamplers{
420420
.sType = VK_STRUCTURE_TYPE_BIND_HEAP_INFO_EXT,

‎examples/raytracingsbtdata/raytracingsbtdata.cpp‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Uses the data section of each shader binding table record to color the background and geometry
55
*
66
* Example by Nate Morrical (https://github.com/natevm)
7-
*
7+
*
88
* Copyright (C) 2019-2025 by Sascha Willems - www.saschawillems.de
99
*
1010
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
@@ -135,7 +135,7 @@ class VulkanExample : public VulkanExampleBase
135135
}
136136
}
137137

138-
/*
138+
/*
139139
Create a scratch buffer to hold temporary data for a ray tracing acceleration structure
140140
*/
141141
RayTracingScratchBuffer createScratchBuffer(VkDeviceSize size)
@@ -171,7 +171,7 @@ class VulkanExample : public VulkanExampleBase
171171
return scratchBuffer;
172172
}
173173

174-
void deleteScratchBuffer(RayTracingScratchBuffer& scratchBuffer)
174+
void deleteScratchBuffer(RayTracingScratchBuffer& scratchBuffer)
175175
{
176176
if (scratchBuffer.memory != VK_NULL_HANDLE) {
177177
vkFreeMemory(device, scratchBuffer.memory, nullptr);
@@ -322,7 +322,7 @@ class VulkanExample : public VulkanExampleBase
322322
VkDeviceOrHostAddressConstKHR vertexBufferDeviceAddress{};
323323
VkDeviceOrHostAddressConstKHR indexBufferDeviceAddress{};
324324
VkDeviceOrHostAddressConstKHR transformBufferDeviceAddress{};
325-
325+
326326
vertexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(vertexBuffer.buffer);
327327
indexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(indexBuffer.buffer);
328328
transformBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(transformBuffer.buffer);
@@ -342,15 +342,15 @@ class VulkanExample : public VulkanExampleBase
342342
accelerationStructureGeometry.geometry.triangles.transformData.deviceAddress = 0;
343343
accelerationStructureGeometry.geometry.triangles.transformData.hostAddress = nullptr;
344344
accelerationStructureGeometry.geometry.triangles.transformData = transformBufferDeviceAddress;
345-
345+
346346
// Get size info
347347
VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfo{};
348348
accelerationStructureBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
349349
accelerationStructureBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
350350
accelerationStructureBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
351351
accelerationStructureBuildGeometryInfo.geometryCount = 1;
352352
accelerationStructureBuildGeometryInfo.pGeometries = &accelerationStructureGeometry;
353-
353+
354354
const uint32_t numTriangles = 1;
355355
VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfo{};
356356
accelerationStructureBuildSizesInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
@@ -462,7 +462,7 @@ class VulkanExample : public VulkanExampleBase
462462
VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfo{};
463463
accelerationStructureBuildSizesInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
464464
vkGetAccelerationStructureBuildSizesKHR(
465-
device,
465+
device,
466466
VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR,
467467
&accelerationStructureBuildGeometryInfo,
468468
&primitive_count,
@@ -549,9 +549,9 @@ class VulkanExample : public VulkanExampleBase
549549
const VkBufferUsageFlags bufferUsageFlags = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
550550
const VkMemoryPropertyFlags memoryUsageFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
551551

552-
// We allocate space for the handle (which is like lambda function pointers to call in the ray tracing pipeline)
552+
// We allocate space for the handle (which is like lambda function pointers to call in the ray tracing pipeline)
553553
// as well as the data to pass to those functions (which act as the variables being "captured" by those lambda functions)
554-
uint32_t bufferSize = vks::tools::alignedSize(handleSize + 3 * sizeof(float), rayTracingPipelineProperties.shaderGroupBaseAlignment);
554+
uint32_t bufferSize = vks::tools::alignedSize(handleSize + (uint32_t)(3 * sizeof(float)), rayTracingPipelineProperties.shaderGroupBaseAlignment);
555555
VK_CHECK_RESULT(vulkanDevice->createBuffer(bufferUsageFlags, memoryUsageFlags, &raygenShaderBindingTable, bufferSize));
556556
VK_CHECK_RESULT(vulkanDevice->createBuffer(bufferUsageFlags, memoryUsageFlags, &missShaderBindingTable, bufferSize));
557557
VK_CHECK_RESULT(vulkanDevice->createBuffer(bufferUsageFlags, memoryUsageFlags, &hitShaderBindingTable, bufferSize));
@@ -763,7 +763,7 @@ class VulkanExample : public VulkanExampleBase
763763

764764
void getEnabledFeatures()
765765
{
766-
// Enable features required for ray tracing using feature chaining via pNext
766+
// Enable features required for ray tracing using feature chaining via pNext
767767
enabledBufferDeviceAddresFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES;
768768
enabledBufferDeviceAddresFeatures.bufferDeviceAddress = VK_TRUE;
769769

@@ -828,7 +828,7 @@ class VulkanExample : public VulkanExampleBase
828828
}
829829

830830
VkCommandBuffer cmdBuffer = drawCmdBuffers[currentBuffer];
831-
831+
832832
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
833833

834834
VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
@@ -845,17 +845,17 @@ class VulkanExample : public VulkanExampleBase
845845
// that we use to store our color data
846846
VkStridedDeviceAddressRegionKHR raygenShaderSbtEntry{};
847847
raygenShaderSbtEntry.deviceAddress = getBufferDeviceAddress(raygenShaderBindingTable.buffer);
848-
raygenShaderSbtEntry.size = vks::tools::alignedSize(handleSizeAligned + 3 * sizeof(float), rayTracingPipelineProperties.shaderGroupBaseAlignment);
848+
raygenShaderSbtEntry.size = vks::tools::alignedSize(handleSizeAligned + (uint32_t)(3 * sizeof(float)), rayTracingPipelineProperties.shaderGroupBaseAlignment);
849849
raygenShaderSbtEntry.stride = raygenShaderSbtEntry.size;
850850

851851
VkStridedDeviceAddressRegionKHR missShaderSbtEntry{};
852852
missShaderSbtEntry.deviceAddress = getBufferDeviceAddress(missShaderBindingTable.buffer);
853-
missShaderSbtEntry.size = vks::tools::alignedSize(handleSizeAligned + 3 * sizeof(float), rayTracingPipelineProperties.shaderGroupBaseAlignment);
853+
missShaderSbtEntry.size = vks::tools::alignedSize(handleSizeAligned + (uint32_t)(3 * sizeof(float)), rayTracingPipelineProperties.shaderGroupBaseAlignment);
854854
missShaderSbtEntry.stride = missShaderSbtEntry.size;
855855

856856
VkStridedDeviceAddressRegionKHR hitShaderSbtEntry{};
857857
hitShaderSbtEntry.deviceAddress = getBufferDeviceAddress(hitShaderBindingTable.buffer);
858-
hitShaderSbtEntry.size = vks::tools::alignedSize(handleSizeAligned + 3 * sizeof(float), rayTracingPipelineProperties.shaderGroupBaseAlignment);
858+
hitShaderSbtEntry.size = vks::tools::alignedSize(handleSizeAligned + (uint32_t)(3 * sizeof(float)), rayTracingPipelineProperties.shaderGroupBaseAlignment);
859859
hitShaderSbtEntry.stride = hitShaderSbtEntry.size;
860860

861861
VkStridedDeviceAddressRegionKHR callableShaderSbtEntry{};

0 commit comments

Comments
 (0)