From 9fddb15a53b723b11894fb9cf1f9e89d7935e2a4 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 3 Apr 2018 17:01:53 -0400 Subject: [PATCH] Round up row and layer byte counts when copying compressed images with sizes that are not integer multiples of block size. --- MoltenVK/MoltenVK/API/mvk_datatypes.h | 17 ++++++++++++----- MoltenVK/MoltenVK/Utility/MVKFoundation.h | 6 ++++++ MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm | 8 ++++---- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h index be0c0961..78f35817 100644 --- a/MoltenVK/MoltenVK/API/mvk_datatypes.h +++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h @@ -118,29 +118,36 @@ float mvkMTLPixelFormatBytesPerTexel(MTLPixelFormat mtlFormat); /** * Returns the size, in bytes, of a row of texels of the specified Vulkan format. + * * For compressed formats, this takes into consideration the compression block size, - * and texelsPerRow should specify the width in texels, not blocks. + * and texelsPerRow should specify the width in texels, not blocks. The result is rounded + * up if texelsPerRow is not an integer multiple of the compression block width. */ size_t mvkVkFormatBytesPerRow(VkFormat vkFormat, uint32_t texelsPerRow); /** - * Returns the size, in bytes, of a row of texels of the specified Metal format. + * Returns the size, in bytes, of a row of texels of the specified Metal format. + * * For compressed formats, this takes into consideration the compression block size, - * and texelsPerRow should specify the width in texels, not blocks. + * and texelsPerRow should specify the width in texels, not blocks. The result is rounded + * up if texelsPerRow is not an integer multiple of the compression block width. */ size_t mvkMTLPixelFormatBytesPerRow(MTLPixelFormat mtlFormat, uint32_t texelsPerRow); /** * Returns the size, in bytes, of a texture layer of the specified Vulkan format. + * * For compressed formats, this takes into consideration the compression block size, - * and texelRowsPerLayer should specify the height in texels, not blocks. + * and texelRowsPerLayer should specify the height in texels, not blocks. The result is + * rounded up if texelRowsPerLayer is not an integer multiple of the compression block height. */ size_t mvkVkFormatBytesPerLayer(VkFormat vkFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer); /** * Returns the size, in bytes, of a texture layer of the specified Metal format. * For compressed formats, this takes into consideration the compression block size, - * and texelRowsPerLayer should specify the height in texels, not blocks. + * and texelRowsPerLayer should specify the height in texels, not blocks. The result is + * rounded up if texelRowsPerLayer is not an integer multiple of the compression block height. */ size_t mvkMTLPixelFormatBytesPerLayer(MTLPixelFormat mtlFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer); diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index 5066df81..5bd8d2a4 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -110,6 +110,12 @@ VkResult mvkNotifyErrorWithText(VkResult vkErr, const char* errFmt, ...) __print #pragma mark - #pragma mark Alignment functions +/** Returns the result of an unsigned integer division, rounded up. */ +static inline size_t mvkCeilingDivide(size_t numerator, size_t denominator) { + if (denominator == 1) { return numerator; } // Short circuit for this very common usecase. + return (numerator + denominator - 1) / denominator; +} + /** Returns whether the specified value is a power-of-two. */ static inline bool mvkIsPowerOfTwo(uintptr_t value) { // Test POT: (x != 0) && ((x & (x - 1)) == 0) diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm index 48b52623..df29bb04 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm @@ -554,20 +554,20 @@ MVK_PUBLIC_SYMBOL float mvkMTLPixelFormatBytesPerTexel(MTLPixelFormat mtlFormat) MVK_PUBLIC_SYMBOL size_t mvkVkFormatBytesPerRow(VkFormat vkFormat, uint32_t texelsPerRow) { const MVKFormatDesc& fmtDesc = formatDescForVkFormat(vkFormat); - return (texelsPerRow / fmtDesc.blockTexelSize.width) * fmtDesc.bytesPerBlock; + return mvkCeilingDivide(texelsPerRow, fmtDesc.blockTexelSize.width) * fmtDesc.bytesPerBlock; } MVK_PUBLIC_SYMBOL size_t mvkMTLPixelFormatBytesPerRow(MTLPixelFormat mtlFormat, uint32_t texelsPerRow) { const MVKFormatDesc& fmtDesc = formatDescForMTLPixelFormat(mtlFormat); - return (texelsPerRow / fmtDesc.blockTexelSize.width) * fmtDesc.bytesPerBlock; + return mvkCeilingDivide(texelsPerRow, fmtDesc.blockTexelSize.width) * fmtDesc.bytesPerBlock; } MVK_PUBLIC_SYMBOL size_t mvkVkFormatBytesPerLayer(VkFormat vkFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer) { - return (texelRowsPerLayer / formatDescForVkFormat(vkFormat).blockTexelSize.height) * bytesPerRow; + return mvkCeilingDivide(texelRowsPerLayer, formatDescForVkFormat(vkFormat).blockTexelSize.height) * bytesPerRow; } MVK_PUBLIC_SYMBOL size_t mvkMTLPixelFormatBytesPerLayer(MTLPixelFormat mtlFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer) { - return (texelRowsPerLayer / formatDescForMTLPixelFormat(mtlFormat).blockTexelSize.height) * bytesPerRow; + return mvkCeilingDivide(texelRowsPerLayer, formatDescForMTLPixelFormat(mtlFormat).blockTexelSize.height) * bytesPerRow; } MVK_PUBLIC_SYMBOL VkFormatProperties mvkVkFormatProperties(VkFormat vkFormat) {