1// 2// Copyright 2019 The ANGLE Project Authors. All rights reserved. 3// Use of this source code is governed by a BSD-style license that can be 4// found in the LICENSE file. 5// 6// mtl_format_utils.mm: 7// Implements Format conversion utilities classes that convert from angle formats 8// to respective MTLPixelFormat and MTLVertexFormat. 9// 10 11#include "libANGLE/renderer/metal/mtl_format_utils.h" 12 13#include "common/debug.h" 14#include "libANGLE/renderer/Format.h" 15#include "libANGLE/renderer/load_functions_table.h" 16#include "libANGLE/renderer/metal/DisplayMtl.h" 17 18namespace rx 19{ 20namespace mtl 21{ 22 23namespace 24{ 25 26bool OverrideTextureCaps(const DisplayMtl *display, angle::FormatID formatId, gl::TextureCaps *caps) 27{ 28 // NOTE(hqle): Auto generate this. 29 switch (formatId) 30 { 31 // NOTE: even though iOS devices don't support filtering depth textures, we still report as 32 // supported here in order for the OES_depth_texture extension to be enabled. 33 // During draw call, the filter modes will be converted to nearest. 34 case angle::FormatID::D16_UNORM: 35 case angle::FormatID::D24_UNORM_S8_UINT: 36 case angle::FormatID::D32_FLOAT_S8X24_UINT: 37 case angle::FormatID::D32_FLOAT: 38 case angle::FormatID::D32_UNORM: 39 caps->texturable = caps->filterable = caps->textureAttachment = caps->renderbuffer = 40 true; 41 return true; 42 default: 43 // NOTE(hqle): Handle more cases 44 return false; 45 } 46} 47 48void GenerateTextureCapsMap(const FormatTable &formatTable, 49 const DisplayMtl *display, 50 gl::TextureCapsMap *capsMapOut, 51 std::vector<GLenum> *compressedFormatsOut, 52 uint32_t *maxSamplesOut) 53{ 54 auto &textureCapsMap = *capsMapOut; 55 auto &compressedFormats = *compressedFormatsOut; 56 57 compressedFormats.clear(); 58 59 auto formatVerifier = [&](const gl::InternalFormat &internalFormatInfo) { 60 angle::FormatID angleFormatId = 61 angle::Format::InternalFormatToID(internalFormatInfo.sizedInternalFormat); 62 const Format &mtlFormat = formatTable.getPixelFormat(angleFormatId); 63 if (!mtlFormat.valid()) 64 { 65 return; 66 } 67 const FormatCaps &formatCaps = mtlFormat.getCaps(); 68 69 const angle::Format &intendedAngleFormat = mtlFormat.intendedAngleFormat(); 70 gl::TextureCaps textureCaps; 71 72 // First let check whether we can override certain special cases. 73 if (!OverrideTextureCaps(display, mtlFormat.intendedFormatId, &textureCaps)) 74 { 75 // Fill the texture caps using pixel format's caps 76 textureCaps.filterable = mtlFormat.getCaps().filterable; 77 textureCaps.renderbuffer = 78 mtlFormat.getCaps().colorRenderable || mtlFormat.getCaps().depthRenderable; 79 textureCaps.texturable = true; 80 textureCaps.blendable = mtlFormat.getCaps().blendable; 81 textureCaps.textureAttachment = textureCaps.renderbuffer; 82 } 83 84 if (formatCaps.multisample) 85 { 86 constexpr uint32_t sampleCounts[] = {2, 4, 8}; 87 for (auto sampleCount : sampleCounts) 88 { 89 if ([display->getMetalDevice() supportsTextureSampleCount:sampleCount]) 90 { 91 textureCaps.sampleCounts.insert(sampleCount); 92 *maxSamplesOut = std::max(*maxSamplesOut, sampleCount); 93 } 94 } 95 } 96 97 textureCapsMap.set(mtlFormat.intendedFormatId, textureCaps); 98 99 if (intendedAngleFormat.isBlock) 100 { 101 compressedFormats.push_back(intendedAngleFormat.glInternalFormat); 102 } 103 }; 104 105 // Texture caps map. 106 const gl::FormatSet &internalFormats = gl::GetAllSizedInternalFormats(); 107 for (const auto internalFormat : internalFormats) 108 { 109 const gl::InternalFormat &internalFormatInfo = 110 gl::GetSizedInternalFormatInfo(internalFormat); 111 112 formatVerifier(internalFormatInfo); 113 } 114} 115 116} // namespace 117 118// FormatBase implementation 119const angle::Format &FormatBase::actualAngleFormat() const 120{ 121 return angle::Format::Get(actualFormatId); 122} 123 124const angle::Format &FormatBase::intendedAngleFormat() const 125{ 126 return angle::Format::Get(intendedFormatId); 127} 128 129// Format implementation 130const gl::InternalFormat &Format::intendedInternalFormat() const 131{ 132 return gl::GetSizedInternalFormatInfo(intendedAngleFormat().glInternalFormat); 133} 134 135const gl::InternalFormat &Format::actualInternalFormat() const 136{ 137 return gl::GetSizedInternalFormatInfo(actualAngleFormat().glInternalFormat); 138} 139 140bool Format::needConversion(angle::FormatID srcFormatId) const 141{ 142 if ((srcFormatId == angle::FormatID::BC1_RGB_UNORM_BLOCK && 143 actualFormatId == angle::FormatID::BC1_RGBA_UNORM_BLOCK) || 144 (srcFormatId == angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK && 145 actualFormatId == angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK)) 146 { 147 // When texture swizzling is available, DXT1 RGB format will be swizzled with RGB1. 148 // WebGL allows unswizzled mapping when swizzling is not available. No need to convert. 149 return false; 150 } 151 if (srcFormatId == angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK && 152 actualFormatId == angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK) 153 { 154 // ETC1 RGB & ETC2 RGB are technically the same. 155 return false; 156 } 157 return srcFormatId != actualFormatId; 158} 159 160bool Format::isPVRTC() const 161{ 162 switch (metalFormat) 163 { 164#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST 165 case MTLPixelFormatPVRTC_RGB_2BPP: 166 case MTLPixelFormatPVRTC_RGB_2BPP_sRGB: 167 case MTLPixelFormatPVRTC_RGB_4BPP: 168 case MTLPixelFormatPVRTC_RGB_4BPP_sRGB: 169 case MTLPixelFormatPVRTC_RGBA_2BPP: 170 case MTLPixelFormatPVRTC_RGBA_2BPP_sRGB: 171 case MTLPixelFormatPVRTC_RGBA_4BPP: 172 case MTLPixelFormatPVRTC_RGBA_4BPP_sRGB: 173 return true; 174#endif 175 default: 176 return false; 177 } 178} 179 180// FormatTable implementation 181angle::Result FormatTable::initialize(const DisplayMtl *display) 182{ 183 mMaxSamples = 0; 184 185 // Initialize native format caps 186 initNativeFormatCaps(display); 187 188 for (size_t i = 0; i < angle::kNumANGLEFormats; ++i) 189 { 190 const auto formatId = static_cast<angle::FormatID>(i); 191 192 mPixelFormatTable[i].init(display, formatId); 193 mPixelFormatTable[i].caps = &mNativePixelFormatCapsTable[mPixelFormatTable[i].metalFormat]; 194 195 if (!mPixelFormatTable[i].caps->depthRenderable && 196 mPixelFormatTable[i].actualFormatId != mPixelFormatTable[i].intendedFormatId) 197 { 198 mPixelFormatTable[i].textureLoadFunctions = angle::GetLoadFunctionsMap( 199 mPixelFormatTable[i].intendedAngleFormat().glInternalFormat, 200 mPixelFormatTable[i].actualFormatId); 201 } 202 203 mVertexFormatTables[0][i].init(formatId, false); 204 mVertexFormatTables[1][i].init(formatId, true); 205 } 206 207 return angle::Result::Continue; 208} 209 210void FormatTable::generateTextureCaps(const DisplayMtl *display, 211 gl::TextureCapsMap *capsMapOut, 212 std::vector<GLenum> *compressedFormatsOut) 213{ 214 GenerateTextureCapsMap(*this, display, capsMapOut, compressedFormatsOut, &mMaxSamples); 215} 216 217const Format &FormatTable::getPixelFormat(angle::FormatID angleFormatId) const 218{ 219 return mPixelFormatTable[static_cast<size_t>(angleFormatId)]; 220} 221const FormatCaps &FormatTable::getNativeFormatCaps(MTLPixelFormat mtlFormat) const 222{ 223 ASSERT(mNativePixelFormatCapsTable.count(mtlFormat)); 224 return mNativePixelFormatCapsTable.at(mtlFormat); 225} 226const VertexFormat &FormatTable::getVertexFormat(angle::FormatID angleFormatId, 227 bool tightlyPacked) const 228{ 229 auto tableIdx = tightlyPacked ? 1 : 0; 230 return mVertexFormatTables[tableIdx][static_cast<size_t>(angleFormatId)]; 231} 232 233void FormatTable::setFormatCaps(MTLPixelFormat formatId, 234 bool filterable, 235 bool writable, 236 bool blendable, 237 bool multisample, 238 bool resolve, 239 bool colorRenderable) 240{ 241 setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable, 242 false); 243} 244 245void FormatTable::setFormatCaps(MTLPixelFormat id, 246 bool filterable, 247 bool writable, 248 bool blendable, 249 bool multisample, 250 bool resolve, 251 bool colorRenderable, 252 bool depthRenderable) 253{ 254 mNativePixelFormatCapsTable[id].filterable = filterable; 255 mNativePixelFormatCapsTable[id].writable = writable; 256 mNativePixelFormatCapsTable[id].colorRenderable = colorRenderable; 257 mNativePixelFormatCapsTable[id].depthRenderable = depthRenderable; 258 mNativePixelFormatCapsTable[id].blendable = blendable; 259 mNativePixelFormatCapsTable[id].multisample = multisample; 260 mNativePixelFormatCapsTable[id].resolve = resolve; 261} 262 263void FormatTable::setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable) 264{ 265 setFormatCaps(formatId, filterable, false, false, false, false, false, false); 266} 267 268void FormatTable::initNativeFormatCaps(const DisplayMtl *display) 269{ 270 initNativeFormatCapsAutogen(display); 271} 272 273} // namespace mtl 274} // namespace rx 275