1// 2// Copyright (c) 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 7// DisplayMtl.mm: Metal implementation of DisplayImpl 8 9#include "libANGLE/renderer/metal/DisplayMtl.h" 10 11#include "libANGLE/Context.h" 12#include "libANGLE/Display.h" 13#include "libANGLE/Surface.h" 14#include "libANGLE/renderer/glslang_wrapper_utils.h" 15#include "libANGLE/renderer/metal/ContextMtl.h" 16#include "libANGLE/renderer/metal/SurfaceMtl.h" 17#include "libANGLE/renderer/metal/mtl_common.h" 18#include "platform/Platform.h" 19 20#include "EGL/eglext.h" 21 22namespace rx 23{ 24 25bool IsMetalDisplayAvailable() 26{ 27 // We only support macos 10.13+ and 11 for now. Since they are requirements for Metal 2.0. 28 if (ANGLE_APPLE_AVAILABLE_XCI(10.13, 13.0, 11)) 29 { 30 return true; 31 } 32 return false; 33} 34 35DisplayImpl *CreateMetalDisplay(const egl::DisplayState &state) 36{ 37 return new DisplayMtl(state); 38} 39 40DisplayMtl::DisplayMtl(const egl::DisplayState &state) 41 : DisplayImpl(state), mUtils(this), mGlslangInitialized(false) 42{} 43 44DisplayMtl::~DisplayMtl() {} 45 46egl::Error DisplayMtl::initialize(egl::Display *display) 47{ 48 ASSERT(IsMetalDisplayAvailable()); 49 50 angle::Result result = initializeImpl(display); 51 if (result != angle::Result::Continue) 52 { 53 return egl::EglNotInitialized(); 54 } 55 return egl::NoError(); 56} 57 58angle::Result DisplayMtl::initializeImpl(egl::Display *display) 59{ 60 ANGLE_MTL_OBJC_SCOPE 61 { 62 mMetalDevice = [MTLCreateSystemDefaultDevice() ANGLE_MTL_AUTORELEASE]; 63 if (!mMetalDevice) 64 { 65 return angle::Result::Stop; 66 } 67 68 mCmdQueue.set([[mMetalDevice.get() newCommandQueue] ANGLE_MTL_AUTORELEASE]); 69 70 mCapsInitialized = false; 71 72 if (!mGlslangInitialized) 73 { 74 GlslangInitialize(); 75 mGlslangInitialized = true; 76 } 77 78 if (!mState.featuresAllDisabled) 79 { 80 initializeFeatures(); 81 } 82 83 ANGLE_TRY(mFormatTable.initialize(this)); 84 85 return mUtils.initialize(); 86 } 87} 88 89void DisplayMtl::terminate() 90{ 91 for (mtl::TextureRef &nullTex : mNullTextures) 92 { 93 nullTex.reset(); 94 } 95 mUtils.onDestroy(); 96 mCmdQueue.reset(); 97 mMetalDevice = nil; 98 mCapsInitialized = false; 99 100 if (mGlslangInitialized) 101 { 102 GlslangRelease(); 103 mGlslangInitialized = false; 104 } 105} 106 107bool DisplayMtl::testDeviceLost() 108{ 109 return false; 110} 111 112egl::Error DisplayMtl::restoreLostDevice(const egl::Display *display) 113{ 114 return egl::NoError(); 115} 116 117std::string DisplayMtl::getVendorString() const 118{ 119 ANGLE_MTL_OBJC_SCOPE 120 { 121 std::string vendorString = "Google Inc."; 122 if (mMetalDevice) 123 { 124 vendorString += " Metal Renderer: "; 125 vendorString += mMetalDevice.get().name.UTF8String; 126 } 127 128 return vendorString; 129 } 130} 131 132DeviceImpl *DisplayMtl::createDevice() 133{ 134 UNIMPLEMENTED(); 135 return nullptr; 136} 137 138egl::Error DisplayMtl::waitClient(const gl::Context *context) 139{ 140 auto contextMtl = GetImplAs<ContextMtl>(context); 141 angle::Result result = contextMtl->finishCommandBuffer(); 142 143 if (result != angle::Result::Continue) 144 { 145 return egl::EglBadAccess(); 146 } 147 return egl::NoError(); 148} 149 150egl::Error DisplayMtl::waitNative(const gl::Context *context, EGLint engine) 151{ 152 UNIMPLEMENTED(); 153 return egl::EglBadAccess(); 154} 155 156SurfaceImpl *DisplayMtl::createWindowSurface(const egl::SurfaceState &state, 157 EGLNativeWindowType window, 158 const egl::AttributeMap &attribs) 159{ 160 return new SurfaceMtl(this, state, window, attribs); 161} 162 163SurfaceImpl *DisplayMtl::createPbufferSurface(const egl::SurfaceState &state, 164 const egl::AttributeMap &attribs) 165{ 166 UNIMPLEMENTED(); 167 return static_cast<SurfaceImpl *>(0); 168} 169 170SurfaceImpl *DisplayMtl::createPbufferFromClientBuffer(const egl::SurfaceState &state, 171 EGLenum buftype, 172 EGLClientBuffer clientBuffer, 173 const egl::AttributeMap &attribs) 174{ 175 UNIMPLEMENTED(); 176 return static_cast<SurfaceImpl *>(0); 177} 178 179SurfaceImpl *DisplayMtl::createPixmapSurface(const egl::SurfaceState &state, 180 NativePixmapType nativePixmap, 181 const egl::AttributeMap &attribs) 182{ 183 UNIMPLEMENTED(); 184 return static_cast<SurfaceImpl *>(0); 185} 186 187ImageImpl *DisplayMtl::createImage(const egl::ImageState &state, 188 const gl::Context *context, 189 EGLenum target, 190 const egl::AttributeMap &attribs) 191{ 192 UNIMPLEMENTED(); 193 return nullptr; 194} 195 196rx::ContextImpl *DisplayMtl::createContext(const gl::State &state, 197 gl::ErrorSet *errorSet, 198 const egl::Config *configuration, 199 const gl::Context *shareContext, 200 const egl::AttributeMap &attribs) 201{ 202 return new ContextMtl(state, errorSet, this); 203} 204 205StreamProducerImpl *DisplayMtl::createStreamProducerD3DTexture( 206 egl::Stream::ConsumerType consumerType, 207 const egl::AttributeMap &attribs) 208{ 209 UNIMPLEMENTED(); 210 return nullptr; 211} 212 213gl::Version DisplayMtl::getMaxSupportedESVersion() const 214{ 215 return mtl::kMaxSupportedGLVersion; 216} 217 218gl::Version DisplayMtl::getMaxConformantESVersion() const 219{ 220 return std::min(getMaxSupportedESVersion(), gl::Version(2, 0)); 221} 222 223EGLSyncImpl *DisplayMtl::createSync(const egl::AttributeMap &attribs) 224{ 225 UNIMPLEMENTED(); 226 return nullptr; 227} 228 229egl::Error DisplayMtl::makeCurrent(egl::Surface *drawSurface, 230 egl::Surface *readSurface, 231 gl::Context *context) 232{ 233 if (!context) 234 { 235 return egl::NoError(); 236 } 237 238 return egl::NoError(); 239} 240 241void DisplayMtl::generateExtensions(egl::DisplayExtensions *outExtensions) const 242{ 243 outExtensions->flexibleSurfaceCompatibility = true; 244} 245 246void DisplayMtl::generateCaps(egl::Caps *outCaps) const {} 247 248void DisplayMtl::populateFeatureList(angle::FeatureList *features) {} 249 250egl::ConfigSet DisplayMtl::generateConfigs() 251{ 252 // NOTE(hqle): generate more config permutations 253 egl::ConfigSet configs; 254 255 const gl::Version &maxVersion = getMaxSupportedESVersion(); 256 ASSERT(maxVersion >= gl::Version(2, 0)); 257 bool supportsES3 = maxVersion >= gl::Version(3, 0); 258 259 egl::Config config; 260 261 // Native stuff 262 config.nativeVisualID = 0; 263 config.nativeVisualType = 0; 264 config.nativeRenderable = EGL_TRUE; 265 266 config.colorBufferType = EGL_RGB_BUFFER; 267 config.luminanceSize = 0; 268 config.alphaMaskSize = 0; 269 270 config.transparentType = EGL_NONE; 271 272 // Pbuffer 273 config.maxPBufferWidth = 4096; 274 config.maxPBufferHeight = 4096; 275 config.maxPBufferPixels = 4096 * 4096; 276 277 // Caveat 278 config.configCaveat = EGL_NONE; 279 280 // Misc 281 config.sampleBuffers = 0; 282 config.samples = 0; 283 config.level = 0; 284 config.bindToTextureRGB = EGL_FALSE; 285 config.bindToTextureRGBA = EGL_FALSE; 286 287 config.surfaceType = EGL_WINDOW_BIT; 288 289 config.minSwapInterval = 1; 290 config.maxSwapInterval = 1; 291 292 config.renderTargetFormat = GL_RGBA8; 293 config.depthStencilFormat = GL_DEPTH24_STENCIL8; 294 295 config.conformant = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0); 296 config.renderableType = config.conformant; 297 298 config.matchNativePixmap = EGL_NONE; 299 300 config.colorComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; 301 302 // Buffer sizes 303 config.redSize = 8; 304 config.greenSize = 8; 305 config.blueSize = 8; 306 config.alphaSize = 8; 307 config.bufferSize = config.redSize + config.greenSize + config.blueSize + config.alphaSize; 308 309 // With DS 310 config.depthSize = 24; 311 config.stencilSize = 8; 312 configs.add(config); 313 314 // With D 315 config.depthSize = 24; 316 config.stencilSize = 0; 317 configs.add(config); 318 319 // With S 320 config.depthSize = 0; 321 config.stencilSize = 8; 322 configs.add(config); 323 324 // No DS 325 config.depthSize = 0; 326 config.stencilSize = 0; 327 configs.add(config); 328 329 return configs; 330} 331 332bool DisplayMtl::isValidNativeWindow(EGLNativeWindowType window) const 333{ 334 NSObject *layer = (__bridge NSObject *)(window); 335 return [layer isKindOfClass:[CALayer class]]; 336} 337 338std::string DisplayMtl::getRendererDescription() const 339{ 340 ANGLE_MTL_OBJC_SCOPE 341 { 342 std::string desc = "Metal Renderer"; 343 344 if (mMetalDevice) 345 { 346 desc += ": "; 347 desc += mMetalDevice.get().name.UTF8String; 348 } 349 350 return desc; 351 } 352} 353 354gl::Caps DisplayMtl::getNativeCaps() const 355{ 356 ensureCapsInitialized(); 357 return mNativeCaps; 358} 359const gl::TextureCapsMap &DisplayMtl::getNativeTextureCaps() const 360{ 361 ensureCapsInitialized(); 362 return mNativeTextureCaps; 363} 364const gl::Extensions &DisplayMtl::getNativeExtensions() const 365{ 366 ensureCapsInitialized(); 367 return mNativeExtensions; 368} 369 370const mtl::TextureRef &DisplayMtl::getNullTexture(const gl::Context *context, gl::TextureType type) 371{ 372 // TODO(hqle): Use rx::IncompleteTextureSet. 373 ContextMtl *contextMtl = mtl::GetImpl(context); 374 if (!mNullTextures[type]) 375 { 376 // initialize content with zeros 377 MTLRegion region = MTLRegionMake2D(0, 0, 1, 1); 378 const uint8_t zeroPixel[4] = {0, 0, 0, 255}; 379 380 const auto &rgbaFormat = getPixelFormat(angle::FormatID::R8G8B8A8_UNORM); 381 382 switch (type) 383 { 384 case gl::TextureType::_2D: 385 (void)(mtl::Texture::Make2DTexture(contextMtl, rgbaFormat, 1, 1, 1, false, false, 386 &mNullTextures[type])); 387 mNullTextures[type]->replaceRegion(contextMtl, region, 0, 0, zeroPixel, 388 sizeof(zeroPixel)); 389 break; 390 case gl::TextureType::CubeMap: 391 (void)(mtl::Texture::MakeCubeTexture(contextMtl, rgbaFormat, 1, 1, false, false, 392 &mNullTextures[type])); 393 for (int f = 0; f < 6; ++f) 394 { 395 mNullTextures[type]->replaceRegion(contextMtl, region, 0, f, zeroPixel, 396 sizeof(zeroPixel)); 397 } 398 break; 399 default: 400 UNREACHABLE(); 401 // NOTE(hqle): Support more texture types. 402 } 403 ASSERT(mNullTextures[type]); 404 } 405 406 return mNullTextures[type]; 407} 408 409void DisplayMtl::ensureCapsInitialized() const 410{ 411 if (mCapsInitialized) 412 { 413 return; 414 } 415 416 mCapsInitialized = true; 417 418 // Reset 419 mNativeCaps = gl::Caps(); 420 421 // Fill extension and texture caps 422 initializeExtensions(); 423 initializeTextureCaps(); 424 425 // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf 426 mNativeCaps.maxElementIndex = std::numeric_limits<GLuint>::max() - 1; 427 mNativeCaps.max3DTextureSize = 2048; 428#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 429 mNativeCaps.max2DTextureSize = 16384; 430 mNativeCaps.maxVaryingVectors = 31; 431 mNativeCaps.maxVertexOutputComponents = 124; 432#else 433 if ([getMetalDevice() supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) 434 { 435 mNativeCaps.max2DTextureSize = 16384; 436 mNativeCaps.maxVertexOutputComponents = 124; 437 mNativeCaps.maxVaryingVectors = mNativeCaps.maxVertexOutputComponents / 4; 438 } 439 else 440 { 441 mNativeCaps.max2DTextureSize = 8192; 442 mNativeCaps.maxVertexOutputComponents = 60; 443 mNativeCaps.maxVaryingVectors = mNativeCaps.maxVertexOutputComponents / 4; 444 } 445#endif 446 447 mNativeCaps.maxArrayTextureLayers = 2048; 448 mNativeCaps.maxLODBias = 0; 449 mNativeCaps.maxCubeMapTextureSize = mNativeCaps.max2DTextureSize; 450 mNativeCaps.maxRenderbufferSize = mNativeCaps.max2DTextureSize; 451 mNativeCaps.minAliasedPointSize = 1; 452 mNativeCaps.maxAliasedPointSize = 511; 453 454 mNativeCaps.minAliasedLineWidth = 1.0f; 455 mNativeCaps.maxAliasedLineWidth = 1.0f; 456 457 mNativeCaps.maxDrawBuffers = mtl::kMaxRenderTargets; 458 mNativeCaps.maxFramebufferWidth = mNativeCaps.max2DTextureSize; 459 mNativeCaps.maxFramebufferHeight = mNativeCaps.max2DTextureSize; 460 mNativeCaps.maxColorAttachments = mtl::kMaxRenderTargets; 461 mNativeCaps.maxViewportWidth = mNativeCaps.max2DTextureSize; 462 mNativeCaps.maxViewportHeight = mNativeCaps.max2DTextureSize; 463 464 // NOTE(hqle): MSAA 465 mNativeCaps.maxSampleMaskWords = 0; 466 mNativeCaps.maxColorTextureSamples = 1; 467 mNativeCaps.maxDepthTextureSamples = 1; 468 mNativeCaps.maxIntegerSamples = 1; 469 470 mNativeCaps.maxVertexAttributes = mtl::kMaxVertexAttribs; 471 mNativeCaps.maxVertexAttribBindings = mtl::kMaxVertexAttribs; 472 mNativeCaps.maxVertexAttribRelativeOffset = std::numeric_limits<GLint>::max(); 473 mNativeCaps.maxVertexAttribStride = std::numeric_limits<GLint>::max(); 474 475 mNativeCaps.maxElementsIndices = std::numeric_limits<GLuint>::max(); 476 mNativeCaps.maxElementsVertices = std::numeric_limits<GLuint>::max(); 477 478 // Looks like all floats are IEEE according to the docs here: 479 mNativeCaps.vertexHighpFloat.setIEEEFloat(); 480 mNativeCaps.vertexMediumpFloat.setIEEEFloat(); 481 mNativeCaps.vertexLowpFloat.setIEEEFloat(); 482 mNativeCaps.fragmentHighpFloat.setIEEEFloat(); 483 mNativeCaps.fragmentMediumpFloat.setIEEEFloat(); 484 mNativeCaps.fragmentLowpFloat.setIEEEFloat(); 485 486 mNativeCaps.vertexHighpInt.setTwosComplementInt(32); 487 mNativeCaps.vertexMediumpInt.setTwosComplementInt(32); 488 mNativeCaps.vertexLowpInt.setTwosComplementInt(32); 489 mNativeCaps.fragmentHighpInt.setTwosComplementInt(32); 490 mNativeCaps.fragmentMediumpInt.setTwosComplementInt(32); 491 mNativeCaps.fragmentLowpInt.setTwosComplementInt(32); 492 493 GLuint maxUniformVectors = mtl::kDefaultUniformsMaxSize / (sizeof(GLfloat) * 4); 494 495 const GLuint maxUniformComponents = maxUniformVectors * 4; 496 497 // Uniforms are implemented using a uniform buffer, so the max number of uniforms we can 498 // support is the max buffer range divided by the size of a single uniform (4X float). 499 mNativeCaps.maxVertexUniformVectors = maxUniformVectors; 500 mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Vertex] = maxUniformComponents; 501 mNativeCaps.maxFragmentUniformVectors = maxUniformVectors; 502 mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Fragment] = maxUniformComponents; 503 504 // NOTE(hqle): support UBO (ES 3.0 feature) 505 mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Vertex] = 0; 506 mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Fragment] = 0; 507 mNativeCaps.maxCombinedUniformBlocks = 0; 508 509 // Note that we currently implement textures as combined image+samplers, so the limit is 510 // the minimum of supported samplers and sampled images. 511 mNativeCaps.maxCombinedTextureImageUnits = mtl::kMaxShaderSamplers; 512 mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment] = mtl::kMaxShaderSamplers; 513 mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex] = mtl::kMaxShaderSamplers; 514 515 // NOTE(hqle): support storage buffer. 516 const uint32_t maxPerStageStorageBuffers = 0; 517 mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] = maxPerStageStorageBuffers; 518 mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] = maxPerStageStorageBuffers; 519 mNativeCaps.maxCombinedShaderStorageBlocks = maxPerStageStorageBuffers; 520 521 // Fill in additional limits for UBOs and SSBOs. 522 mNativeCaps.maxUniformBufferBindings = 0; 523 mNativeCaps.maxUniformBlockSize = 0; 524 mNativeCaps.uniformBufferOffsetAlignment = 0; 525 526 mNativeCaps.maxShaderStorageBufferBindings = 0; 527 mNativeCaps.maxShaderStorageBlockSize = 0; 528 mNativeCaps.shaderStorageBufferOffsetAlignment = 0; 529 530 // NOTE(hqle): support UBO 531 for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes) 532 { 533 mNativeCaps.maxCombinedShaderUniformComponents[shaderType] = maxUniformComponents; 534 } 535 536 mNativeCaps.maxCombinedShaderOutputResources = 0; 537 538 mNativeCaps.maxTransformFeedbackInterleavedComponents = 539 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; 540 mNativeCaps.maxTransformFeedbackSeparateAttributes = 541 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS; 542 mNativeCaps.maxTransformFeedbackSeparateComponents = 543 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS; 544 545 // NOTE(hqle): support MSAA. 546 mNativeCaps.maxSamples = 1; 547} 548 549void DisplayMtl::initializeExtensions() const 550{ 551 // Reset 552 mNativeExtensions = gl::Extensions(); 553 554 // Enable this for simple buffer readback testing, but some functionality is missing. 555 // NOTE(hqle): Support full mapBufferRange extension. 556 mNativeExtensions.mapBufferOES = true; 557 mNativeExtensions.mapBufferRange = false; 558 mNativeExtensions.textureStorage = true; 559 mNativeExtensions.drawBuffers = false; 560 mNativeExtensions.fragDepth = true; 561 mNativeExtensions.framebufferBlit = false; 562 mNativeExtensions.framebufferMultisample = false; 563 mNativeExtensions.copyTexture = false; 564 mNativeExtensions.copyCompressedTexture = false; 565 mNativeExtensions.debugMarker = false; 566 mNativeExtensions.robustness = true; 567 mNativeExtensions.textureBorderClampOES = false; // not implemented yet 568 mNativeExtensions.translatedShaderSource = true; 569 mNativeExtensions.discardFramebuffer = true; 570 571 // Enable EXT_blend_minmax 572 mNativeExtensions.blendMinMax = true; 573 574 mNativeExtensions.eglImageOES = false; 575 mNativeExtensions.eglImageExternalOES = false; 576 // NOTE(hqle): Support GL_OES_EGL_image_external_essl3. 577 mNativeExtensions.eglImageExternalEssl3OES = false; 578 579 mNativeExtensions.memoryObject = false; 580 mNativeExtensions.memoryObjectFd = false; 581 582 mNativeExtensions.semaphore = false; 583 mNativeExtensions.semaphoreFd = false; 584 585 mNativeExtensions.instancedArraysANGLE = mFeatures.hasBaseVertexInstancedDraw.enabled; 586 mNativeExtensions.instancedArraysEXT = mNativeExtensions.instancedArraysANGLE; 587 588 mNativeExtensions.robustBufferAccessBehavior = false; 589 590 mNativeExtensions.eglSyncOES = false; 591 592 // NOTE(hqle): support occlusion query 593 mNativeExtensions.occlusionQueryBoolean = false; 594 595 mNativeExtensions.disjointTimerQuery = false; 596 mNativeExtensions.queryCounterBitsTimeElapsed = false; 597 mNativeExtensions.queryCounterBitsTimestamp = false; 598 599 mNativeExtensions.textureFilterAnisotropic = true; 600 mNativeExtensions.maxTextureAnisotropy = 16; 601 602 // NOTE(hqle): Support true NPOT textures. 603 mNativeExtensions.textureNPOTOES = false; 604 605 mNativeExtensions.texture3DOES = false; 606 607 mNativeExtensions.standardDerivativesOES = true; 608 609 mNativeExtensions.elementIndexUintOES = true; 610} 611 612void DisplayMtl::initializeTextureCaps() const 613{ 614 mNativeTextureCaps.clear(); 615 616 mFormatTable.generateTextureCaps(this, &mNativeTextureCaps, 617 &mNativeCaps.compressedTextureFormats); 618 619 // Re-verify texture extensions. 620 mNativeExtensions.setTextureExtensionSupport(mNativeTextureCaps); 621 622 // Disable all depth buffer and stencil buffer readback extensions until we need them 623 mNativeExtensions.readDepthNV = false; 624 mNativeExtensions.readStencilNV = false; 625 mNativeExtensions.depthBufferFloat2NV = false; 626} 627 628void DisplayMtl::initializeFeatures() 629{ 630 // default values: 631 mFeatures.hasBaseVertexInstancedDraw.enabled = true; 632 mFeatures.hasDepthTextureFiltering.enabled = false; 633 mFeatures.hasNonUniformDispatch.enabled = true; 634 mFeatures.hasTextureSwizzle.enabled = false; 635 mFeatures.allowSeparatedDepthStencilBuffers.enabled = false; 636 637#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 638 mFeatures.hasDepthTextureFiltering.enabled = true; 639 640 // Texture swizzle is only supported if macos sdk 10.15 is present 641# if defined(__MAC_10_15) 642 if (ANGLE_APPLE_AVAILABLE_XC(10.15, 13.0)) 643 { 644 // The runtime OS must be MacOS 10.15+ or Mac Catalyst for this to be supported: 645 ANGLE_FEATURE_CONDITION((&mFeatures), hasTextureSwizzle, 646 [getMetalDevice() supportsFamily:MTLGPUFamilyMac2]); 647 } 648# endif 649#elif TARGET_OS_IOS 650 // Base Vertex drawing is only supported since GPU family 3. 651 ANGLE_FEATURE_CONDITION((&mFeatures), hasBaseVertexInstancedDraw, 652 [getMetalDevice() supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]); 653 654 ANGLE_FEATURE_CONDITION((&mFeatures), hasNonUniformDispatch, 655 [getMetalDevice() supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]); 656 657# if !TARGET_OS_SIMULATOR 658 mFeatures.allowSeparatedDepthStencilBuffers.enabled = true; 659# endif 660#endif 661 662 angle::PlatformMethods *platform = ANGLEPlatformCurrent(); 663 platform->overrideFeaturesMtl(platform, &mFeatures); 664} 665 666} // namespace rx 667