| // |
| // Copyright 2019 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // mtl_format_utils.mm: |
| // Implements Format conversion utilities classes that convert from angle formats |
| // to respective MTLPixelFormat and MTLVertexFormat. |
| // |
| |
| #include "libANGLE/renderer/metal/mtl_format_utils.h" |
| |
| #include "common/debug.h" |
| #include "libANGLE/renderer/Format.h" |
| #include "libANGLE/renderer/load_functions_table.h" |
| #include "libANGLE/renderer/metal/DisplayMtl.h" |
| |
| namespace rx |
| { |
| namespace mtl |
| { |
| |
| namespace priv |
| { |
| |
| template <typename T> |
| inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) |
| { |
| return reinterpret_cast<T*>(data + (y * rowPitch) + (z * depthPitch)); |
| } |
| |
| template <typename T> |
| inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) |
| { |
| return reinterpret_cast<const T*>(data + (y * rowPitch) + (z * depthPitch)); |
| } |
| |
| } // namespace priv |
| |
| void LoadS8D24S8ToD32FX24S8(size_t width, |
| size_t height, |
| size_t depth, |
| const uint8_t *input, |
| size_t inputRowPitch, |
| size_t inputDepthPitch, |
| uint8_t *output, |
| size_t outputRowPitch, |
| size_t outputDepthPitch) |
| { |
| for (size_t z = 0; z < depth; z++) |
| { |
| for (size_t y = 0; y < height; y++) |
| { |
| const uint32_t *source = |
| priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); |
| float *destDepth = |
| priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); |
| uint32_t *destStencil = |
| priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch) + |
| 1; |
| for (size_t x = 0; x < width; x++) |
| { |
| destDepth[x * 2] = ((source[x] >> 8) & 0xFFFFFF) / static_cast<float>(0xFFFFFF); |
| destStencil[x * 2] = (source[x] & 0xFF); |
| } |
| } |
| } |
| } |
| |
| static LoadImageFunctionInfo DEPTH24_STENCIL8_to_D32_FLOAT_X24S8_UINT(GLenum type) |
| { |
| switch(type) |
| { |
| case GL_UNSIGNED_INT_24_8: |
| return LoadImageFunctionInfo(LoadS8D24S8ToD32FX24S8, true); |
| default: |
| UNREACHABLE(); |
| return LoadImageFunctionInfo(nullptr, true); |
| } |
| } |
| |
| |
| LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, angle::FormatID angleFormat) |
| { |
| if(internalFormat == GL_DEPTH24_STENCIL8 && angleFormat == angle::FormatID::D32_FLOAT_S8X24_UINT) |
| { |
| return DEPTH24_STENCIL8_to_D32_FLOAT_X24S8_UINT; |
| } |
| return angle::GetLoadFunctionsMap(internalFormat, angleFormat); |
| } |
| |
| namespace |
| { |
| |
| bool OverrideTextureCaps(const DisplayMtl *display, angle::FormatID formatId, gl::TextureCaps *caps) |
| { |
| // NOTE(hqle): Auto generate this. |
| switch (formatId) |
| { |
| // NOTE: even though iOS devices don't support filtering depth textures, we still report as |
| // supported here in order for the OES_depth_texture extension to be enabled. |
| // During draw call, the filter modes will be converted to nearest. |
| case angle::FormatID::D16_UNORM: |
| case angle::FormatID::D24_UNORM_S8_UINT: |
| case angle::FormatID::D32_FLOAT_S8X24_UINT: |
| case angle::FormatID::D32_FLOAT: |
| case angle::FormatID::D32_UNORM: |
| caps->texturable = caps->filterable = caps->textureAttachment = caps->renderbuffer = |
| true; |
| return true; |
| default: |
| // NOTE(hqle): Handle more cases |
| return false; |
| } |
| } |
| |
| void GenerateTextureCapsMap(const FormatTable &formatTable, |
| const DisplayMtl *display, |
| gl::TextureCapsMap *capsMapOut, |
| std::vector<GLenum> *compressedFormatsOut, |
| uint32_t *maxSamplesOut) |
| { |
| auto &textureCapsMap = *capsMapOut; |
| auto &compressedFormats = *compressedFormatsOut; |
| |
| compressedFormats.clear(); |
| |
| auto formatVerifier = [&](const gl::InternalFormat &internalFormatInfo) { |
| angle::FormatID angleFormatId = |
| angle::Format::InternalFormatToID(internalFormatInfo.sizedInternalFormat); |
| const Format &mtlFormat = formatTable.getPixelFormat(angleFormatId); |
| if (!mtlFormat.valid()) |
| { |
| return; |
| } |
| const FormatCaps &formatCaps = mtlFormat.getCaps(); |
| |
| const angle::Format &intendedAngleFormat = mtlFormat.intendedAngleFormat(); |
| gl::TextureCaps textureCaps; |
| |
| // First let check whether we can override certain special cases. |
| if (!OverrideTextureCaps(display, mtlFormat.intendedFormatId, &textureCaps)) |
| { |
| // Fill the texture caps using pixel format's caps |
| textureCaps.filterable = mtlFormat.getCaps().filterable; |
| textureCaps.renderbuffer = |
| mtlFormat.getCaps().colorRenderable || mtlFormat.getCaps().depthRenderable; |
| textureCaps.texturable = true; |
| textureCaps.textureAttachment = textureCaps.renderbuffer; |
| textureCaps.blendable = mtlFormat.getCaps().blendable; |
| } |
| |
| if (formatCaps.multisample) |
| { |
| constexpr uint32_t sampleCounts[] = {2, 4, 8}; |
| for (auto sampleCount : sampleCounts) |
| { |
| if ([display->getMetalDevice() supportsTextureSampleCount:sampleCount]) |
| { |
| textureCaps.sampleCounts.insert(sampleCount); |
| *maxSamplesOut = std::max(*maxSamplesOut, sampleCount); |
| } |
| } |
| } |
| |
| textureCapsMap.set(mtlFormat.intendedFormatId, textureCaps); |
| |
| if (intendedAngleFormat.isBlock) |
| { |
| compressedFormats.push_back(intendedAngleFormat.glInternalFormat); |
| } |
| }; |
| |
| // Texture caps map. |
| const gl::FormatSet &internalFormats = gl::GetAllSizedInternalFormats(); |
| for (const auto internalFormat : internalFormats) |
| { |
| const gl::InternalFormat &internalFormatInfo = |
| gl::GetSizedInternalFormatInfo(internalFormat); |
| |
| formatVerifier(internalFormatInfo); |
| } |
| } |
| |
| } // namespace |
| |
| // FormatBase implementation |
| const angle::Format &FormatBase::actualAngleFormat() const |
| { |
| return angle::Format::Get(actualFormatId); |
| } |
| |
| const angle::Format &FormatBase::intendedAngleFormat() const |
| { |
| return angle::Format::Get(intendedFormatId); |
| } |
| |
| // Format implementation |
| const gl::InternalFormat &Format::intendedInternalFormat() const |
| { |
| return gl::GetSizedInternalFormatInfo(intendedAngleFormat().glInternalFormat); |
| } |
| |
| const gl::InternalFormat &Format::actualInternalFormat() const |
| { |
| return gl::GetSizedInternalFormatInfo(actualAngleFormat().glInternalFormat); |
| } |
| |
| bool Format::needConversion(angle::FormatID srcFormatId) const |
| { |
| if ((srcFormatId == angle::FormatID::BC1_RGB_UNORM_BLOCK && |
| actualFormatId == angle::FormatID::BC1_RGBA_UNORM_BLOCK) || |
| (srcFormatId == angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK && |
| actualFormatId == angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK)) |
| { |
| // When texture swizzling is available, DXT1 RGB format will be swizzled with RGB1. |
| // WebGL allows unswizzled mapping when swizzling is not available. No need to convert. |
| return false; |
| } |
| return srcFormatId != actualFormatId; |
| } |
| |
| bool Format::isPVRTC() const |
| { |
| switch (metalFormat) |
| { |
| #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST |
| case MTLPixelFormatPVRTC_RGB_2BPP: |
| case MTLPixelFormatPVRTC_RGB_2BPP_sRGB: |
| case MTLPixelFormatPVRTC_RGB_4BPP: |
| case MTLPixelFormatPVRTC_RGB_4BPP_sRGB: |
| case MTLPixelFormatPVRTC_RGBA_2BPP: |
| case MTLPixelFormatPVRTC_RGBA_2BPP_sRGB: |
| case MTLPixelFormatPVRTC_RGBA_4BPP: |
| case MTLPixelFormatPVRTC_RGBA_4BPP_sRGB: |
| return true; |
| #endif |
| default: |
| return false; |
| } |
| } |
| |
| // FormatTable implementation |
| angle::Result FormatTable::initialize(const DisplayMtl *display) |
| { |
| mMaxSamples = 0; |
| |
| // Initialize native format caps |
| initNativeFormatCaps(display); |
| |
| for (size_t i = 0; i < angle::kNumANGLEFormats; ++i) |
| { |
| const auto formatId = static_cast<angle::FormatID>(i); |
| |
| mPixelFormatTable[i].init(display, formatId); |
| mPixelFormatTable[i].caps = &mNativePixelFormatCapsTable[mPixelFormatTable[i].metalFormat]; |
| |
| if (mPixelFormatTable[i].actualFormatId != mPixelFormatTable[i].intendedFormatId) |
| { |
| mPixelFormatTable[i].textureLoadFunctions = mtl::GetLoadFunctionsMap( |
| mPixelFormatTable[i].intendedAngleFormat().glInternalFormat, |
| mPixelFormatTable[i].actualFormatId); |
| } |
| |
| mVertexFormatTables[0][i].init(formatId, false); |
| mVertexFormatTables[1][i].init(formatId, true); |
| } |
| |
| // NOTE(hqle): Work-around AMD's issue that D24S8 format sometimes returns zero during sampling: |
| if (display->getRendererDescription().find("AMD") != std::string::npos) |
| { |
| const auto& d32format = mPixelFormatTable[static_cast<uint32_t>(angle::FormatID::D32_FLOAT_S8X24_UINT)]; |
| |
| // Fallback to D32_FLOAT_S8X24_UINT. |
| Format &format = |
| mPixelFormatTable[static_cast<uint32_t>(angle::FormatID::D24_UNORM_S8_UINT)]; |
| format.actualFormatId = angle::FormatID::D32_FLOAT_S8X24_UINT; |
| format.metalFormat = MTLPixelFormatDepth32Float_Stencil8; |
| format.initFunction = d32format.initFunction; |
| format.textureLoadFunctions = d32format.textureLoadFunctions; |
| format.caps = &mNativePixelFormatCapsTable[MTLPixelFormatDepth32Float_Stencil8]; |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| void FormatTable::generateTextureCaps(const DisplayMtl *display, |
| gl::TextureCapsMap *capsMapOut, |
| std::vector<GLenum> *compressedFormatsOut) |
| { |
| GenerateTextureCapsMap(*this, display, capsMapOut, compressedFormatsOut, &mMaxSamples); |
| } |
| |
| const Format &FormatTable::getPixelFormat(angle::FormatID angleFormatId) const |
| { |
| return mPixelFormatTable[static_cast<size_t>(angleFormatId)]; |
| } |
| const FormatCaps &FormatTable::getNativeFormatCaps(MTLPixelFormat mtlFormat) const |
| { |
| ASSERT(mNativePixelFormatCapsTable.count(mtlFormat)); |
| return mNativePixelFormatCapsTable.at(mtlFormat); |
| } |
| const VertexFormat &FormatTable::getVertexFormat(angle::FormatID angleFormatId, |
| bool tightlyPacked) const |
| { |
| auto tableIdx = tightlyPacked ? 1 : 0; |
| return mVertexFormatTables[tableIdx][static_cast<size_t>(angleFormatId)]; |
| } |
| |
| void FormatTable::setFormatCaps(MTLPixelFormat formatId, |
| bool filterable, |
| bool writable, |
| bool blendable, |
| bool multisample, |
| bool resolve, |
| bool colorRenderable) |
| { |
| setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable, |
| false, 0); |
| } |
| void FormatTable::setFormatCaps(MTLPixelFormat formatId, |
| bool filterable, |
| bool writable, |
| bool blendable, |
| bool multisample, |
| bool resolve, |
| bool colorRenderable, |
| NSUInteger pixelBytes, |
| NSUInteger channels) |
| { |
| setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable, |
| false, pixelBytes, channels); |
| } |
| |
| void FormatTable::setFormatCaps(MTLPixelFormat formatId, |
| bool filterable, |
| bool writable, |
| bool blendable, |
| bool multisample, |
| bool resolve, |
| bool colorRenderable, |
| bool depthRenderable) |
| { |
| setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable, |
| depthRenderable, 0, 0); |
| } |
| void FormatTable::setFormatCaps(MTLPixelFormat id, |
| bool filterable, |
| bool writable, |
| bool blendable, |
| bool multisample, |
| bool resolve, |
| bool colorRenderable, |
| bool depthRenderable, |
| NSUInteger pixelBytes, |
| NSUInteger channels) |
| { |
| mNativePixelFormatCapsTable[id].filterable = filterable; |
| mNativePixelFormatCapsTable[id].writable = writable; |
| mNativePixelFormatCapsTable[id].colorRenderable = colorRenderable; |
| mNativePixelFormatCapsTable[id].depthRenderable = depthRenderable; |
| mNativePixelFormatCapsTable[id].blendable = blendable; |
| mNativePixelFormatCapsTable[id].multisample = multisample; |
| mNativePixelFormatCapsTable[id].resolve = resolve; |
| mNativePixelFormatCapsTable[id].pixelBytes = pixelBytes; |
| mNativePixelFormatCapsTable[id].pixelBytesMSAA = pixelBytes; |
| mNativePixelFormatCapsTable[id].channels = channels; |
| if (channels != 0) |
| mNativePixelFormatCapsTable[id].alignment = MAX(pixelBytes / channels, 1U); |
| } |
| |
| void FormatTable::setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable) |
| { |
| setFormatCaps(formatId, filterable, false, false, false, false, false, false); |
| } |
| |
| void FormatTable::adjustFormatCapsForDevice(id<MTLDevice> device, |
| MTLPixelFormat id, |
| bool supportsiOS2, |
| bool supportsiOS4) |
| { |
| #if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST) |
| |
| NSUInteger pixelBytesRender = mNativePixelFormatCapsTable[id].pixelBytes; |
| NSUInteger pixelBytesRenderMSAA = mNativePixelFormatCapsTable[id].pixelBytesMSAA; |
| NSUInteger alignment = mNativePixelFormatCapsTable[id].alignment; |
| |
| // Override the current pixelBytesRender |
| # define SPECIFIC(_pixelFormat, _pixelBytesRender) \ |
| case _pixelFormat: \ |
| pixelBytesRender = _pixelBytesRender; \ |
| pixelBytesRenderMSAA = _pixelBytesRender; \ |
| alignment = \ |
| supportsiOS4 ? _pixelBytesRender / mNativePixelFormatCapsTable[id].channels : 4; \ |
| break |
| // Override the current pixel bytes render, and MSAA |
| # define SPECIFIC_MSAA(_pixelFormat, _pixelBytesRender, _pixelBytesRenderMSAA) \ |
| case _pixelFormat: \ |
| pixelBytesRender = _pixelBytesRender; \ |
| pixelBytesRenderMSAA = _pixelBytesRenderMSAA; \ |
| alignment = \ |
| supportsiOS4 ? _pixelBytesRender / mNativePixelFormatCapsTable[id].channels : 4; \ |
| break |
| // Override the current pixelBytesRender, and alignment |
| # define SPECIFIC_ALIGN(_pixelFormat, _pixelBytesRender, _alignment) \ |
| case _pixelFormat: \ |
| pixelBytesRender = _pixelBytesRender; \ |
| pixelBytesRenderMSAA = _pixelBytesRender; \ |
| alignment = _alignment; \ |
| break |
| |
| if (!mNativePixelFormatCapsTable[id].compressed) |
| { |
| // On AppleGPUFamily4+, there is no 4byte minimum requirement for render targets |
| uint32_t minSize = supportsiOS4 ? 1U : 4U; |
| pixelBytesRender = MAX(mNativePixelFormatCapsTable[id].pixelBytes, minSize); |
| pixelBytesRenderMSAA = pixelBytesRender; |
| alignment = |
| supportsiOS4 ? MAX(pixelBytesRender / mNativePixelFormatCapsTable[id].channels, 1U) : 4; |
| } |
| |
| // This list of tables starts from a general multi-platform table, |
| // to specific platforms (i.e. ios2, ios4) inheriting from the previous tables |
| |
| // Start off with the general case |
| switch ((NSUInteger)id) |
| { |
| SPECIFIC(MTLPixelFormatB5G6R5Unorm, 4U); |
| SPECIFIC(MTLPixelFormatA1BGR5Unorm, 4U); |
| SPECIFIC(MTLPixelFormatABGR4Unorm, 4U); |
| SPECIFIC(MTLPixelFormatBGR5A1Unorm, 4U); |
| |
| SPECIFIC(MTLPixelFormatRGBA8Unorm, 4U); |
| SPECIFIC(MTLPixelFormatBGRA8Unorm, 4U); |
| |
| SPECIFIC_MSAA(MTLPixelFormatRGBA8Unorm_sRGB, 4U, 8U); |
| SPECIFIC_MSAA(MTLPixelFormatBGRA8Unorm_sRGB, 4U, 8U); |
| SPECIFIC_MSAA(MTLPixelFormatRGBA8Snorm, 4U, 8U); |
| SPECIFIC_MSAA(MTLPixelFormatRGB10A2Uint, 4U, 8U); |
| |
| SPECIFIC(MTLPixelFormatRGB10A2Unorm, 8U); |
| SPECIFIC(MTLPixelFormatBGR10A2Unorm, 8U); |
| |
| SPECIFIC(MTLPixelFormatRG11B10Float, 8U); |
| |
| SPECIFIC(MTLPixelFormatRGB9E5Float, 8U); |
| |
| SPECIFIC(MTLPixelFormatStencil8, 1U); |
| } |
| |
| // Override based ios2 |
| if (supportsiOS2) |
| { |
| switch ((NSUInteger)id) |
| { |
| SPECIFIC(MTLPixelFormatB5G6R5Unorm, 8U); |
| SPECIFIC(MTLPixelFormatA1BGR5Unorm, 8U); |
| SPECIFIC(MTLPixelFormatABGR4Unorm, 8U); |
| SPECIFIC(MTLPixelFormatBGR5A1Unorm, 8U); |
| SPECIFIC_MSAA(MTLPixelFormatRGBA8Unorm, 4U, 8U); |
| SPECIFIC_MSAA(MTLPixelFormatBGRA8Unorm, 4U, 8U); |
| } |
| } |
| |
| // Override based on ios4 |
| if (supportsiOS4) |
| { |
| switch ((NSUInteger)id) |
| { |
| SPECIFIC_ALIGN(MTLPixelFormatB5G6R5Unorm, 6U, 2U); |
| SPECIFIC(MTLPixelFormatRGBA8Unorm, 4U); |
| SPECIFIC(MTLPixelFormatBGRA8Unorm, 4U); |
| |
| SPECIFIC(MTLPixelFormatRGBA8Unorm_sRGB, 4U); |
| SPECIFIC(MTLPixelFormatBGRA8Unorm_sRGB, 4U); |
| |
| SPECIFIC(MTLPixelFormatRGBA8Snorm, 4U); |
| |
| SPECIFIC_ALIGN(MTLPixelFormatRGB10A2Unorm, 4U, 4U); |
| SPECIFIC_ALIGN(MTLPixelFormatBGR10A2Unorm, 4U, 4U); |
| SPECIFIC(MTLPixelFormatRGB10A2Uint, 8U); |
| |
| SPECIFIC_ALIGN(MTLPixelFormatRG11B10Float, 4U, 4U); |
| |
| SPECIFIC_ALIGN(MTLPixelFormatRGB9E5Float, 4U, 4U); |
| } |
| } |
| mNativePixelFormatCapsTable[id].pixelBytes = pixelBytesRender; |
| mNativePixelFormatCapsTable[id].pixelBytesMSAA = pixelBytesRenderMSAA; |
| mNativePixelFormatCapsTable[id].alignment = alignment; |
| |
| # undef SPECIFIC |
| # undef SPECIFIC_ALIGN |
| # undef SPECIFIC_MSAA |
| #endif |
| // macOS does not need to perform any additoinal adjustment. These values are only used to check |
| // valid MRT sizes on iOS. |
| } |
| |
| void FormatTable::initNativeFormatCaps(const DisplayMtl *display) |
| { |
| const angle::FeaturesMtl &featuresMtl = display->getFeatures(); |
| // Skip auto resolve if either hasDepth/StencilAutoResolve or allowMultisampleStoreAndResolve |
| // feature are disabled. |
| bool supportDepthAutoResolve = featuresMtl.hasDepthAutoResolve.enabled && |
| featuresMtl.allowMultisampleStoreAndResolve.enabled; |
| bool supportStencilAutoResolve = featuresMtl.hasStencilAutoResolve.enabled && |
| featuresMtl.allowMultisampleStoreAndResolve.enabled; |
| bool supportDepthStencilAutoResolve = supportDepthAutoResolve && supportStencilAutoResolve; |
| |
| // Source: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf |
| // clang-format off |
| |
| // | formatId | filterable | writable | blendable | multisample | resolve | colorRenderable | bytesPerChannel | channel |
| setFormatCaps(MTLPixelFormatA8Unorm, true, false, false, false, false, false, 1U, 1U); |
| setFormatCaps(MTLPixelFormatR8Unorm, true, true, true, true, true, true, 1U, 1U); |
| setFormatCaps(MTLPixelFormatR8Snorm, true, true, true, true, display->supportsEitherGPUFamily(2, 1), true, 1U, 1U); |
| setFormatCaps(MTLPixelFormatR16Unorm, true, true, true, true, display->supportsEitherGPUFamily(1, 1), true, 2U, 1U); |
| setFormatCaps(MTLPixelFormatR16Snorm, true, true, true, true, display->supportsEitherGPUFamily(1, 1), true, 2U, 1U); |
| setFormatCaps(MTLPixelFormatRG8Unorm, true, true, true, true, true, true, 1U, 1U); |
| setFormatCaps(MTLPixelFormatRG8Snorm, true, true, true, true, display->supportsEitherGPUFamily(2, 1), true, 2U, 2U); |
| setFormatCaps(MTLPixelFormatRG16Unorm, true, true, true, true, display->supportsEitherGPUFamily(1, 1), true, 4U, 2U); |
| setFormatCaps(MTLPixelFormatRG16Snorm, true, true, true, true, display->supportsEitherGPUFamily(1, 1), true, 4U, 2U); |
| setFormatCaps(MTLPixelFormatRGBA16Unorm, true, true, true, true, display->supportsEitherGPUFamily(1, 1), true, 8U, 4U); |
| setFormatCaps(MTLPixelFormatRGBA16Snorm, true, true, true, true, display->supportsEitherGPUFamily(1, 1), true, 8U, 4U); |
| setFormatCaps(MTLPixelFormatRGBA16Float, true, true, true, true, true, true, 8U, 4U); |
| |
| // | formatId | filterable | writable | blendable | multisample | resolve | colorRenderable | |
| setFormatCaps(MTLPixelFormatRGBA8Unorm, true, true, true, true, true, true, 4U, 4U); |
| setFormatCaps(MTLPixelFormatRGBA8Unorm_sRGB, true, display->supportsIOSGPUFamily(2), true, true, true, true, 4U, 4U); |
| setFormatCaps(MTLPixelFormatRGBA8Snorm, true, true, true, true, display->supportsEitherGPUFamily(2, 1), true, 4U, 4U); |
| setFormatCaps(MTLPixelFormatBGRA8Unorm, true, true, true, true, true, true, 4U, 4U); |
| setFormatCaps(MTLPixelFormatBGRA8Unorm_sRGB, true, display->supportsIOSGPUFamily(2), true, true, true, true, 4U, 4U); |
| |
| // | formatId | filterable | writable | blendable | multisample | resolve | colorRenderable | |
| setFormatCaps(MTLPixelFormatR16Float, true, true, true, true, true, true, 2U, 1U); |
| setFormatCaps(MTLPixelFormatRG16Float, true, true, true, true, true, true, 4U, 2U); |
| setFormatCaps(MTLPixelFormatR32Float, display->supportsEitherGPUFamily(1,1), true, true, true, display->supportsEitherGPUFamily(1,1), true, 4U, 1U); |
| |
| #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST |
| // | formatId | filterable | writable | blendable | multisample | resolve | colorRenderable | |
| setFormatCaps(MTLPixelFormatB5G6R5Unorm, true, false, true, true, true, true, 2U, 3U); |
| setFormatCaps(MTLPixelFormatABGR4Unorm, true, false, true, true, true, true, 2U, 4U); |
| setFormatCaps(MTLPixelFormatBGR5A1Unorm, true, false, true, true, true, true, 2U, 4U); |
| setFormatCaps(MTLPixelFormatA1BGR5Unorm, true, false, true, true, true, true, 2U, 4U); |
| #endif |
| |
| // | formatId | filterable | writable | blendable | multisample | resolve | colorRenderable | |
| setFormatCaps(MTLPixelFormatBGR10A2Unorm, true, display->supportsEitherGPUFamily(3, 1), true, true, true, true, 4U, 4U); |
| setFormatCaps(MTLPixelFormatRGB10A2Unorm, true, display->supportsEitherGPUFamily(3, 1), true, true, true, true, 4U, 4U); |
| setFormatCaps(MTLPixelFormatRGB10A2Uint, false, display->supportsEitherGPUFamily(3, 1), false, true, false, true, 4U, 4U); |
| setFormatCaps(MTLPixelFormatRG11B10Float, true, display->supportsEitherGPUFamily(3, 1), true, true, true, true, 4U, 3U); |
| |
| // | formatId | filterable | writable | blendable | multisample | resolve | colorRenderable | |
| setFormatCaps(MTLPixelFormatRGB9E5Float, true, display->supportsIOSGPUFamily(3), display->supportsIOSGPUFamily(1), display->supportsIOSGPUFamily(1), display->supportsIOSGPUFamily(1), display->supportsIOSGPUFamily(1), 4U, 3U); |
| |
| // | formatId | filterable | writable | blendable | multisample | resolve | colorRenderable | |
| setFormatCaps(MTLPixelFormatR8Uint, false, true, false, true, false, true, 1U, 1U); |
| setFormatCaps(MTLPixelFormatR8Sint, false, true, false, true, false, true, 1U, 1U); |
| setFormatCaps(MTLPixelFormatR16Uint, false, true, false, true, false, true, 2U, 1U); |
| setFormatCaps(MTLPixelFormatR16Sint, false, true, false, true, false, true, 4U, 1U); |
| setFormatCaps(MTLPixelFormatRG8Uint, false, true, false, true, false, true, 2U, 2U); |
| setFormatCaps(MTLPixelFormatRG8Sint, false, true, false, true, false, true, 2U, 2U); |
| setFormatCaps(MTLPixelFormatR32Uint, false, true, false, display->supportsEitherGPUFamily(1,1), false, true, 4U, 1U); |
| setFormatCaps(MTLPixelFormatR32Sint, false, true, false, display->supportsEitherGPUFamily(1,1), false, true, 4U, 1U); |
| setFormatCaps(MTLPixelFormatRG16Uint, false, true, false, true, false, true, 4U, 2U); |
| setFormatCaps(MTLPixelFormatRG16Sint, false, true, false, true, false, true, 4U, 2U); |
| setFormatCaps(MTLPixelFormatRGBA8Uint, false, true, false, true, false, true, 4U, 1U); |
| setFormatCaps(MTLPixelFormatRGBA8Sint, false, true, false, true, false, true, 4U, 1U); |
| setFormatCaps(MTLPixelFormatRG32Uint, false, true, false, display->supportsEitherGPUFamily(1,1), false, true, 8U, 2U); |
| setFormatCaps(MTLPixelFormatRG32Sint, false, true, false, display->supportsEitherGPUFamily(1,1), false, true, 8U, 2U); |
| setFormatCaps(MTLPixelFormatRGBA16Uint, false, true, false, true, false, true, 8U, 4U); |
| setFormatCaps(MTLPixelFormatRGBA16Sint, false, true, false, true, false, true, 8U, 4U); |
| setFormatCaps(MTLPixelFormatRGBA32Uint, false, true, false, display->supportsEitherGPUFamily(1,1), false, true, 16U, 4U); |
| setFormatCaps(MTLPixelFormatRGBA32Sint, false, true, false, display->supportsEitherGPUFamily(1,1), false, true, 16U, 4U); |
| |
| // | formatId | filterable | writable | blendable | multisample | resolve | colorRenderable | |
| setFormatCaps(MTLPixelFormatRG32Float, display->supportsEitherGPUFamily(1,1), true, true, display->supportsEitherGPUFamily(1,1), display->supportsEitherGPUFamily(1,1), true, 8U, 2U); |
| setFormatCaps(MTLPixelFormatRGBA32Float, display->supportsEitherGPUFamily(1,1), true, display->supportsEitherGPUFamily(1,1), display->supportsEitherGPUFamily(1,1), display->supportsEitherGPUFamily(1,1), true, 16U, 4U); |
| |
| // | formatId | filterable | writable | blendable | multisample | resolve | colorRenderable | depthRenderable | |
| setFormatCaps(MTLPixelFormatDepth32Float, display->supportsEitherGPUFamily(1,1), false, false, true, supportDepthAutoResolve, false, true, 4U, 1U); |
| setFormatCaps(MTLPixelFormatStencil8, false, false, false, true, false, false, true, 1U, 1U); |
| setFormatCaps(MTLPixelFormatDepth32Float_Stencil8, display->supportsEitherGPUFamily(1,1), false, false, true, supportDepthStencilAutoResolve, false, true, 8U, 2U); |
| //ToDo: @available on 13.0 |
| setFormatCaps(MTLPixelFormatDepth16Unorm, true, false, false, true, supportDepthAutoResolve, false, true, 2U, 1U); |
| #if TARGET_OS_OSX || TARGET_OS_MACCATALYST |
| setFormatCaps(MTLPixelFormatDepth24Unorm_Stencil8, display->supportsEitherGPUFamily(1,1), false, false, true, supportDepthStencilAutoResolve, false, display->supportsEitherGPUFamily(1,1), 4U, 2U); |
| |
| setCompressedFormatCaps(MTLPixelFormatBC1_RGBA, true); |
| setCompressedFormatCaps(MTLPixelFormatBC1_RGBA_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatBC2_RGBA, true); |
| setCompressedFormatCaps(MTLPixelFormatBC2_RGBA_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatBC3_RGBA, true); |
| setCompressedFormatCaps(MTLPixelFormatBC3_RGBA_sRGB, true); |
| #else |
| setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_2BPP, true); |
| setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_2BPP_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_4BPP, true); |
| setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_4BPP_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_2BPP, true); |
| setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_2BPP_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_4BPP, true); |
| setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_4BPP_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatEAC_R11Unorm, true); |
| setCompressedFormatCaps(MTLPixelFormatEAC_R11Snorm, true); |
| setCompressedFormatCaps(MTLPixelFormatEAC_RG11Unorm, true); |
| setCompressedFormatCaps(MTLPixelFormatEAC_RG11Snorm, true); |
| setCompressedFormatCaps(MTLPixelFormatEAC_RGBA8, true); |
| setCompressedFormatCaps(MTLPixelFormatEAC_RGBA8_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatETC2_RGB8, true); |
| setCompressedFormatCaps(MTLPixelFormatETC2_RGB8_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatETC2_RGB8A1, true); |
| setCompressedFormatCaps(MTLPixelFormatETC2_RGB8A1_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_4x4_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_5x4_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_5x5_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_6x5_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_6x6_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_8x5_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_8x6_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_8x8_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_10x5_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_10x6_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_10x8_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_10x10_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_12x10_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_12x12_sRGB, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_4x4_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_5x4_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_5x5_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_6x5_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_6x6_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_8x5_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_8x6_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_8x8_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_10x5_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_10x6_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_10x8_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_10x10_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_12x10_LDR, true); |
| setCompressedFormatCaps(MTLPixelFormatASTC_12x12_LDR, true); |
| #endif |
| // clang-format on |
| } |
| |
| } // namespace mtl |
| } // namespace rx |