From 88fa93f1deac2d2df25eb3099de75818cdc89878 Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Thu, 2 Jan 2020 11:35:23 -0700 Subject: [PATCH] Add support for ASTC textures on iOS / Metal (#1992) --- RELEASE_NOTES.md | 1 + .../include/private/backend/BackendUtils.h | 8 ++- filament/backend/src/BackendUtils.cpp | 49 +++++++++++++++- filament/backend/src/metal/MetalEnums.h | 58 ++++++++++--------- filament/backend/src/metal/MetalHandles.h | 1 + filament/backend/src/metal/MetalHandles.mm | 4 +- 6 files changed, 90 insertions(+), 31 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index be3d62fcbd..e4bde79c6e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -12,6 +12,7 @@ A new header is inserted each time a *tag* is created. - Fixed incorrect punctual light binning (affected Metal and Vulkan backends). - Fixed crash when using a Metal headless SwapChain with an Intel integrated GPU. - cmgen now places KTX files directly in the specified deployment folder. +- Added support for ASTC textures on iOS with Metal backend. ## v1.4.3 diff --git a/filament/backend/include/private/backend/BackendUtils.h b/filament/backend/include/private/backend/BackendUtils.h index 1b16c07ab6..e6ccaca0d2 100644 --- a/filament/backend/include/private/backend/BackendUtils.h +++ b/filament/backend/include/private/backend/BackendUtils.h @@ -28,10 +28,16 @@ namespace backend { size_t getFormatSize(TextureFormat format) noexcept; /** - * For compressed texture formats, returns the number of horizontal pixels per block. Otherwise + * For compressed texture formats, returns the number of horizontal texels per block. Otherwise * returns 0. */ size_t getBlockWidth(TextureFormat format) noexcept; +/** + * For compressed texture formats, returns the number of vertical texels per block. Otherwise + * returns 0. + */ +size_t getBlockHeight(TextureFormat format) noexcept; + } // namespace backend } // namespace filament diff --git a/filament/backend/src/BackendUtils.cpp b/filament/backend/src/BackendUtils.cpp index b024513ebf..55ecc32f3e 100644 --- a/filament/backend/src/BackendUtils.cpp +++ b/filament/backend/src/BackendUtils.cpp @@ -188,7 +188,6 @@ size_t getBlockWidth(TextureFormat format) noexcept { case TextureFormat::SRGB8_ALPHA8_ASTC_5x4: case TextureFormat::SRGB8_ALPHA8_ASTC_5x5: return 5; - return 5; case TextureFormat::RGBA_ASTC_6x5: case TextureFormat::RGBA_ASTC_6x6: @@ -225,6 +224,54 @@ size_t getBlockWidth(TextureFormat format) noexcept { } } +size_t getBlockHeight(TextureFormat format) noexcept { + switch (format) { + case TextureFormat::RGBA_ASTC_4x4: + case TextureFormat::SRGB8_ALPHA8_ASTC_4x4: + case TextureFormat::RGBA_ASTC_5x4: + case TextureFormat::SRGB8_ALPHA8_ASTC_5x4: + return 4; + + case TextureFormat::RGBA_ASTC_5x5: + case TextureFormat::SRGB8_ALPHA8_ASTC_5x5: + case TextureFormat::RGBA_ASTC_6x5: + case TextureFormat::SRGB8_ALPHA8_ASTC_6x5: + case TextureFormat::RGBA_ASTC_8x5: + case TextureFormat::SRGB8_ALPHA8_ASTC_8x5: + case TextureFormat::RGBA_ASTC_10x5: + case TextureFormat::SRGB8_ALPHA8_ASTC_10x5: + return 5; + + case TextureFormat::RGBA_ASTC_6x6: + case TextureFormat::SRGB8_ALPHA8_ASTC_6x6: + case TextureFormat::RGBA_ASTC_8x6: + case TextureFormat::SRGB8_ALPHA8_ASTC_8x6: + case TextureFormat::RGBA_ASTC_10x6: + case TextureFormat::SRGB8_ALPHA8_ASTC_10x6: + return 6; + + case TextureFormat::RGBA_ASTC_8x8: + case TextureFormat::SRGB8_ALPHA8_ASTC_8x8: + case TextureFormat::RGBA_ASTC_10x8: + case TextureFormat::SRGB8_ALPHA8_ASTC_10x8: + return 8; + + case TextureFormat::RGBA_ASTC_10x10: + case TextureFormat::SRGB8_ALPHA8_ASTC_10x10: + case TextureFormat::RGBA_ASTC_12x10: + case TextureFormat::SRGB8_ALPHA8_ASTC_12x10: + return 10; + + case TextureFormat::RGBA_ASTC_12x12: + case TextureFormat::SRGB8_ALPHA8_ASTC_12x12: + return 12; + + default: + // Most compressed formats use square blocks, only ASTC is special. + return getBlockWidth(format); + } +} + } // namespace backend } // namespace filament diff --git a/filament/backend/src/metal/MetalEnums.h b/filament/backend/src/metal/MetalEnums.h index 7c894c5058..d05bbba699 100644 --- a/filament/backend/src/metal/MetalEnums.h +++ b/filament/backend/src/metal/MetalEnums.h @@ -239,34 +239,36 @@ constexpr inline MTLPixelFormat getMetalFormat(TextureFormat format) noexcept { case TextureFormat::DXT1_RGB: return MTLPixelFormatInvalid; #endif - case TextureFormat::RGBA_ASTC_4x4: - case TextureFormat::RGBA_ASTC_5x4: - case TextureFormat::RGBA_ASTC_5x5: - case TextureFormat::RGBA_ASTC_6x5: - case TextureFormat::RGBA_ASTC_6x6: - case TextureFormat::RGBA_ASTC_8x5: - case TextureFormat::RGBA_ASTC_8x6: - case TextureFormat::RGBA_ASTC_8x8: - case TextureFormat::RGBA_ASTC_10x5: - case TextureFormat::RGBA_ASTC_10x6: - case TextureFormat::RGBA_ASTC_10x8: - case TextureFormat::RGBA_ASTC_10x10: - case TextureFormat::RGBA_ASTC_12x10: - case TextureFormat::RGBA_ASTC_12x12: - case TextureFormat::SRGB8_ALPHA8_ASTC_4x4: - case TextureFormat::SRGB8_ALPHA8_ASTC_5x4: - case TextureFormat::SRGB8_ALPHA8_ASTC_5x5: - case TextureFormat::SRGB8_ALPHA8_ASTC_6x5: - case TextureFormat::SRGB8_ALPHA8_ASTC_6x6: - case TextureFormat::SRGB8_ALPHA8_ASTC_8x5: - case TextureFormat::SRGB8_ALPHA8_ASTC_8x6: - case TextureFormat::SRGB8_ALPHA8_ASTC_8x8: - case TextureFormat::SRGB8_ALPHA8_ASTC_10x5: - case TextureFormat::SRGB8_ALPHA8_ASTC_10x6: - case TextureFormat::SRGB8_ALPHA8_ASTC_10x8: - case TextureFormat::SRGB8_ALPHA8_ASTC_10x10: - case TextureFormat::SRGB8_ALPHA8_ASTC_12x10: - case TextureFormat::SRGB8_ALPHA8_ASTC_12x12: +#if defined(IOS) + case TextureFormat::RGBA_ASTC_4x4: return MTLPixelFormatASTC_4x4_HDR; + case TextureFormat::RGBA_ASTC_5x4: return MTLPixelFormatASTC_5x4_HDR; + case TextureFormat::RGBA_ASTC_5x5: return MTLPixelFormatASTC_5x5_HDR; + case TextureFormat::RGBA_ASTC_6x5: return MTLPixelFormatASTC_6x5_HDR; + case TextureFormat::RGBA_ASTC_6x6: return MTLPixelFormatASTC_6x6_HDR; + case TextureFormat::RGBA_ASTC_8x5: return MTLPixelFormatASTC_8x5_HDR; + case TextureFormat::RGBA_ASTC_8x6: return MTLPixelFormatASTC_8x6_HDR; + case TextureFormat::RGBA_ASTC_8x8: return MTLPixelFormatASTC_8x8_HDR; + case TextureFormat::RGBA_ASTC_10x5: return MTLPixelFormatASTC_10x5_HDR; + case TextureFormat::RGBA_ASTC_10x6: return MTLPixelFormatASTC_10x6_HDR; + case TextureFormat::RGBA_ASTC_10x8: return MTLPixelFormatASTC_10x8_HDR; + case TextureFormat::RGBA_ASTC_10x10: return MTLPixelFormatASTC_10x10_HDR; + case TextureFormat::RGBA_ASTC_12x10: return MTLPixelFormatASTC_12x10_HDR; + case TextureFormat::RGBA_ASTC_12x12: return MTLPixelFormatASTC_12x12_HDR; + case TextureFormat::SRGB8_ALPHA8_ASTC_4x4: return MTLPixelFormatASTC_4x4_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_5x4: return MTLPixelFormatASTC_5x4_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_5x5: return MTLPixelFormatASTC_5x5_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_6x5: return MTLPixelFormatASTC_6x5_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_6x6: return MTLPixelFormatASTC_6x6_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_8x5: return MTLPixelFormatASTC_8x5_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_8x6: return MTLPixelFormatASTC_8x6_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_8x8: return MTLPixelFormatASTC_8x8_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_10x5: return MTLPixelFormatASTC_10x5_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_10x6: return MTLPixelFormatASTC_10x6_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_10x8: return MTLPixelFormatASTC_10x8_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_10x10: return MTLPixelFormatASTC_10x10_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_12x10: return MTLPixelFormatASTC_12x10_sRGB; + case TextureFormat::SRGB8_ALPHA8_ASTC_12x12: return MTLPixelFormatASTC_12x12_sRGB; +#endif default: case TextureFormat::UNUSED: diff --git a/filament/backend/src/metal/MetalHandles.h b/filament/backend/src/metal/MetalHandles.h index cdd099a2c1..703f757081 100644 --- a/filament/backend/src/metal/MetalHandles.h +++ b/filament/backend/src/metal/MetalHandles.h @@ -117,6 +117,7 @@ struct MetalTexture : public HwTexture { id texture = nil; uint8_t bytesPerElement; // The number of bytes per pixel, or block (for compressed texture formats). uint8_t blockWidth; // The number of horizontal pixels per block (only for compressed texture formats). + uint8_t blockHeight; // The number of vertical pixels per block (only for compressed texture formats). TextureReshaper reshaper; MTLPixelFormat metalPixelFormat; }; diff --git a/filament/backend/src/metal/MetalHandles.mm b/filament/backend/src/metal/MetalHandles.mm index 4e526455b2..4e0b0f65df 100644 --- a/filament/backend/src/metal/MetalHandles.mm +++ b/filament/backend/src/metal/MetalHandles.mm @@ -214,6 +214,7 @@ MetalTexture::MetalTexture(MetalContext& context, backend::SamplerType target, u bytesPerElement = static_cast(getFormatSize(reshapedFormat)); assert(bytesPerElement > 0); blockWidth = static_cast(getBlockWidth(reshapedFormat)); + blockHeight = static_cast(getBlockHeight(reshapedFormat)); ASSERT_POSTCONDITION(metalPixelFormat != MTLPixelFormatInvalid, "Pixel format not supported."); @@ -304,12 +305,13 @@ void MetalTexture::loadSlice(uint32_t level, uint32_t xoffset, uint32_t yoffset, if (data.type == PixelDataType::COMPRESSED) { assert(blockWidth > 0); + assert(blockHeight > 0); // From https://developer.apple.com/documentation/metal/mtltexture/1515464-replaceregion: // For an ordinary or packed pixel format, the stride, in bytes, between rows of source // data. For a compressed pixel format, the stride is the number of bytes from the // beginning of one row of blocks to the beginning of the next. const NSUInteger blocksPerRow = std::ceil(width / (float) blockWidth); - const NSUInteger blocksPerCol = std::ceil(height / (float) blockWidth); + const NSUInteger blocksPerCol = std::ceil(height / (float) blockHeight); bytesPerRow = bytesPerElement * blocksPerRow; bytesPerSlice = bytesPerRow * blocksPerCol; }