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 7// DisplayMtl.mm: Metal implementation of DisplayImpl 8 9#include "libANGLE/renderer/metal/DisplayMtl.h" 10 11#include "common/system_utils.h" 12#include "gpu_info_util/SystemInfo.h" 13#include "libANGLE/Context.h" 14#include "libANGLE/Display.h" 15#include "libANGLE/Surface.h" 16#include "libANGLE/renderer/driver_utils.h" 17#include "libANGLE/renderer/glslang_wrapper_utils.h" 18#include "libANGLE/renderer/metal/CompilerMtl.h" 19#include "libANGLE/renderer/metal/ContextMtl.h" 20#include "libANGLE/renderer/metal/DeviceMtl.h" 21#include "libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h" 22#include "libANGLE/renderer/metal/ImageMtl.h" 23#include "libANGLE/renderer/metal/SurfaceMtl.h" 24#include "libANGLE/renderer/metal/SyncMtl.h" 25#include "libANGLE/renderer/metal/mtl_common.h" 26#include "libANGLE/renderer/metal/shaders/mtl_default_shaders_src_autogen.inc" 27#include "libANGLE/trace.h" 28#include "platform/Platform.h" 29 30#ifdef ANGLE_METAL_XCODE_BUILDS_SHADERS 31# include "libANGLE/renderer/metal/mtl_default_shaders_compiled.inc" 32#endif 33 34#include "EGL/eglext.h" 35 36namespace rx 37{ 38 39static EGLint GetDepthSize(GLint internalformat) 40{ 41 switch (internalformat) 42 { 43 case GL_STENCIL_INDEX8: 44 return 0; 45 case GL_DEPTH_COMPONENT16: 46 return 16; 47 case GL_DEPTH_COMPONENT24: 48 return 24; 49 case GL_DEPTH_COMPONENT32_OES: 50 return 32; 51 case GL_DEPTH_COMPONENT32F: 52 return 32; 53 case GL_DEPTH24_STENCIL8: 54 return 24; 55 case GL_DEPTH32F_STENCIL8: 56 return 32; 57 default: 58 // UNREACHABLE(internalformat); 59 return 0; 60 } 61} 62 63static EGLint GetStencilSize(GLint internalformat) 64{ 65 switch (internalformat) 66 { 67 case GL_STENCIL_INDEX8: 68 return 8; 69 case GL_DEPTH_COMPONENT16: 70 return 0; 71 case GL_DEPTH_COMPONENT24: 72 return 0; 73 case GL_DEPTH_COMPONENT32_OES: 74 return 0; 75 case GL_DEPTH_COMPONENT32F: 76 return 0; 77 case GL_DEPTH24_STENCIL8: 78 return 8; 79 case GL_DEPTH32F_STENCIL8: 80 return 8; 81 default: 82 // UNREACHABLE(internalformat); 83 return 0; 84 } 85} 86 87bool IsMetalDisplayAvailable() 88{ 89 // We only support macos 10.13+ and 11 for now. Since they are requirements for Metal 2.0. 90#if TARGET_OS_SIMULATOR 91 if (ANGLE_APPLE_AVAILABLE_XCI(10.13, 13.0, 13)) 92#else 93 if (ANGLE_APPLE_AVAILABLE_XCI(10.13, 13.0, 11)) 94#endif 95 { 96 return true; 97 } 98 return false; 99} 100 101DisplayImpl *CreateMetalDisplay(const egl::DisplayState &state) 102{ 103 return new DisplayMtl(state); 104} 105 106struct DefaultShaderAsyncInfoMtl 107{ 108 mtl::AutoObjCPtr<id<MTLLibrary>> defaultShaders; 109 mtl::AutoObjCPtr<NSError *> defaultShadersCompileError; 110 111 // Synchronization primitives for compiling default shaders in back-ground 112 std::condition_variable cv; 113 std::mutex lock; 114 115 bool compiled = false; 116}; 117 118DisplayMtl::DisplayMtl(const egl::DisplayState &state) 119 : DisplayImpl(state), mStateCache(mFeatures), mUtils(this) 120{} 121 122DisplayMtl::~DisplayMtl() {} 123 124egl::Error DisplayMtl::initialize(egl::Display *display) 125{ 126 ASSERT(IsMetalDisplayAvailable()); 127 128 angle::Result result = initializeImpl(display); 129 if (result != angle::Result::Continue) 130 { 131 return egl::EglNotInitialized(); 132 } 133 return egl::NoError(); 134} 135 136angle::Result DisplayMtl::initializeImpl(egl::Display *display) 137{ 138 ANGLE_MTL_OBJC_SCOPE 139 { 140 mMetalDevice = getMetalDeviceMatchingAttribute(display->getAttributeMap()); 141 // If we can't create a device, fail initialization. 142 if (!mMetalDevice.get()) 143 { 144 return angle::Result::Stop; 145 } 146 147 mMetalDeviceVendorId = mtl::GetDeviceVendorId(mMetalDevice); 148 149 mCmdQueue.set([[mMetalDevice newCommandQueue] ANGLE_MTL_AUTORELEASE]); 150 151 mCapsInitialized = false; 152#if ANGLE_ENABLE_METAL_SPIRV 153 ANGLE_TRACE_EVENT0("gpu.angle,startup", "GlslangWarmup"); 154 sh::InitializeGlslang(); 155#endif 156 157 if (!mState.featuresAllDisabled) 158 { 159 initializeFeatures(); 160 } 161 162 ANGLE_TRY(mFormatTable.initialize(this)); 163 ANGLE_TRY(initializeShaderLibrary()); 164 165 return mUtils.initialize(); 166 } 167} 168 169void DisplayMtl::terminate() 170{ 171 mUtils.onDestroy(); 172 mCmdQueue.reset(); 173 mDefaultShadersAsyncInfo = nullptr; 174 mMetalDevice = nil; 175#if ANGLE_MTL_EVENT_AVAILABLE 176 mSharedEventListener = nil; 177#endif 178 mCapsInitialized = false; 179 180 mMetalDeviceVendorId = 0; 181#if ANGLE_ENABLE_METAL_SPIRV 182 sh::FinalizeGlslang(); 183#endif 184} 185 186bool DisplayMtl::testDeviceLost() 187{ 188 return false; 189} 190 191egl::Error DisplayMtl::restoreLostDevice(const egl::Display *display) 192{ 193 return egl::NoError(); 194} 195 196std::string DisplayMtl::getRendererDescription() 197{ 198 ANGLE_MTL_OBJC_SCOPE 199 { 200 std::string desc = "ANGLE Metal Renderer"; 201 202 if (mMetalDevice) 203 { 204 desc += ": "; 205 desc += mMetalDevice.get().name.UTF8String; 206 } 207 208 return desc; 209 } 210} 211 212std::string DisplayMtl::getVendorString() 213{ 214 return GetVendorString(mMetalDeviceVendorId); 215} 216 217std::string DisplayMtl::getVersionString(bool includeFullVersion) 218{ 219 ANGLE_MTL_OBJC_SCOPE 220 { 221 NSProcessInfo *procInfo = [NSProcessInfo processInfo]; 222 return procInfo.operatingSystemVersionString.UTF8String; 223 } 224} 225 226DeviceImpl *DisplayMtl::createDevice() 227{ 228 return new DeviceMtl(); 229} 230 231mtl::AutoObjCPtr<id<MTLDevice>> DisplayMtl::getMetalDeviceMatchingAttribute( 232 const egl::AttributeMap &attribs) 233{ 234#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST) 235 auto deviceList = mtl::adoptObjCObj(MTLCopyAllDevices()); 236 237 EGLAttrib high = attribs.get(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE, 0); 238 EGLAttrib low = attribs.get(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE, 0); 239 uint64_t deviceId = 240 angle::GetSystemDeviceIdFromParts(static_cast<uint32_t>(high), static_cast<uint32_t>(low)); 241 // Check EGL_ANGLE_platform_angle_device_id to see if a device was specified. 242 if (deviceId != 0) 243 { 244 for (id<MTLDevice> device in deviceList.get()) 245 { 246 if ([device registryID] == deviceId) 247 { 248 return device; 249 } 250 } 251 } 252 253 auto externalGPUs = 254 mtl::adoptObjCObj<NSMutableArray<id<MTLDevice>>>([[NSMutableArray alloc] init]); 255 auto integratedGPUs = 256 mtl::adoptObjCObj<NSMutableArray<id<MTLDevice>>>([[NSMutableArray alloc] init]); 257 auto discreteGPUs = 258 mtl::adoptObjCObj<NSMutableArray<id<MTLDevice>>>([[NSMutableArray alloc] init]); 259 for (id<MTLDevice> device in deviceList.get()) 260 { 261 if (device.removable) 262 { 263 [externalGPUs addObject:device]; 264 } 265 else if (device.lowPower) 266 { 267 [integratedGPUs addObject:device]; 268 } 269 else 270 { 271 [discreteGPUs addObject:device]; 272 } 273 } 274 // TODO(kpiddington: External GPU support. Do we prefer high power / low bandwidth for general 275 // WebGL applications? 276 // Can we support hot-swapping in GPU's? 277 if (attribs.get(EGL_POWER_PREFERENCE_ANGLE, 0) == EGL_HIGH_POWER_ANGLE) 278 { 279 // Search for a discrete GPU first. 280 for (id<MTLDevice> device in discreteGPUs.get()) 281 { 282 if (![device isHeadless]) 283 return device; 284 } 285 } 286 else if (attribs.get(EGL_POWER_PREFERENCE_ANGLE, 0) == EGL_LOW_POWER_ANGLE) 287 { 288 // If we've selected a low power device, look through integrated devices. 289 for (id<MTLDevice> device in integratedGPUs.get()) 290 { 291 if (![device isHeadless]) 292 return device; 293 } 294 } 295 296 const std::string preferredDeviceString = angle::GetPreferredDeviceString(); 297 if (!preferredDeviceString.empty()) 298 { 299 for (id<MTLDevice> device in deviceList.get()) 300 { 301 if ([device.name.lowercaseString 302 containsString:[NSString stringWithUTF8String:preferredDeviceString.c_str()]]) 303 { 304 NSLog(@"Using Metal Device: %@", [device name]); 305 return device; 306 } 307 } 308 } 309 310#endif 311 // If we can't find anything, or are on a platform that doesn't support power options, create a 312 // default device. 313 return mtl::adoptObjCObj(MTLCreateSystemDefaultDevice()); 314} 315 316egl::Error DisplayMtl::waitClient(const gl::Context *context) 317{ 318 auto contextMtl = GetImplAs<ContextMtl>(context); 319 angle::Result result = contextMtl->finishCommandBuffer(); 320 321 if (result != angle::Result::Continue) 322 { 323 return egl::EglBadAccess(); 324 } 325 return egl::NoError(); 326} 327 328egl::Error DisplayMtl::waitNative(const gl::Context *context, EGLint engine) 329{ 330 UNIMPLEMENTED(); 331 return egl::NoError(); 332} 333 334SurfaceImpl *DisplayMtl::createWindowSurface(const egl::SurfaceState &state, 335 EGLNativeWindowType window, 336 const egl::AttributeMap &attribs) 337{ 338 return new WindowSurfaceMtl(this, state, window, attribs); 339} 340 341SurfaceImpl *DisplayMtl::createPbufferSurface(const egl::SurfaceState &state, 342 const egl::AttributeMap &attribs) 343{ 344 return new PBufferSurfaceMtl(this, state, attribs); 345} 346 347SurfaceImpl *DisplayMtl::createPbufferFromClientBuffer(const egl::SurfaceState &state, 348 EGLenum buftype, 349 EGLClientBuffer clientBuffer, 350 const egl::AttributeMap &attribs) 351{ 352 switch (buftype) 353 { 354 case EGL_IOSURFACE_ANGLE: 355 return new IOSurfaceSurfaceMtl(this, state, clientBuffer, attribs); 356 default: 357 UNREACHABLE(); 358 } 359 return nullptr; 360} 361 362SurfaceImpl *DisplayMtl::createPixmapSurface(const egl::SurfaceState &state, 363 NativePixmapType nativePixmap, 364 const egl::AttributeMap &attribs) 365{ 366 UNIMPLEMENTED(); 367 return static_cast<SurfaceImpl *>(0); 368} 369 370ImageImpl *DisplayMtl::createImage(const egl::ImageState &state, 371 const gl::Context *context, 372 EGLenum target, 373 const egl::AttributeMap &attribs) 374{ 375 return new ImageMtl(state, context); 376} 377 378rx::ContextImpl *DisplayMtl::createContext(const gl::State &state, 379 gl::ErrorSet *errorSet, 380 const egl::Config *configuration, 381 const gl::Context *shareContext, 382 const egl::AttributeMap &attribs) 383{ 384 return new ContextMtl(state, errorSet, attribs, this); 385} 386 387StreamProducerImpl *DisplayMtl::createStreamProducerD3DTexture( 388 egl::Stream::ConsumerType consumerType, 389 const egl::AttributeMap &attribs) 390{ 391 UNIMPLEMENTED(); 392 return nullptr; 393} 394 395ShareGroupImpl *DisplayMtl::createShareGroup() 396{ 397 return new ShareGroupMtl(); 398} 399 400ExternalImageSiblingImpl *DisplayMtl::createExternalImageSibling(const gl::Context *context, 401 EGLenum target, 402 EGLClientBuffer buffer, 403 const egl::AttributeMap &attribs) 404{ 405 switch (target) 406 { 407 case EGL_METAL_TEXTURE_ANGLE: 408 return new TextureImageSiblingMtl(buffer); 409 410 default: 411 UNREACHABLE(); 412 return nullptr; 413 } 414} 415 416gl::Version DisplayMtl::getMaxSupportedESVersion() const 417{ 418#if TARGET_OS_SIMULATOR 419 // Simulator should be able to support ES3, despite not supporting iOS GPU 420 // Family 3 in its entirety. 421 // FIXME: None of the feature conditions are checked for simulator support. 422 return gl::Version(3, 0); 423#else 424 if (supportsEitherGPUFamily(3, 1)) 425 { 426 return mtl::kMaxSupportedGLVersion; 427 } 428 return gl::Version(2, 0); 429#endif 430} 431 432gl::Version DisplayMtl::getMaxConformantESVersion() const 433{ 434 return std::min(getMaxSupportedESVersion(), gl::Version(3, 0)); 435} 436 437EGLSyncImpl *DisplayMtl::createSync(const egl::AttributeMap &attribs) 438{ 439 return new EGLSyncMtl(attribs); 440} 441 442egl::Error DisplayMtl::makeCurrent(egl::Display *display, 443 egl::Surface *drawSurface, 444 egl::Surface *readSurface, 445 gl::Context *context) 446{ 447 if (!context) 448 { 449 return egl::NoError(); 450 } 451 452 return egl::NoError(); 453} 454 455void DisplayMtl::generateExtensions(egl::DisplayExtensions *outExtensions) const 456{ 457 outExtensions->iosurfaceClientBuffer = true; 458 outExtensions->surfacelessContext = true; 459 outExtensions->noConfigContext = true; 460 outExtensions->displayTextureShareGroup = true; 461 outExtensions->displaySemaphoreShareGroup = true; 462 outExtensions->mtlTextureClientBuffer = true; 463 464 if (mFeatures.hasEvents.enabled) 465 { 466 // MTLSharedEvent is only available since Metal 2.1 467 outExtensions->fenceSync = true; 468 outExtensions->waitSync = true; 469 } 470 471 // Note that robust resource initialization is not yet implemented. We only expose 472 // this extension so that ANGLE can be initialized in Chrome. WebGL will fail to use 473 // this extension (anglebug.com/4929) 474 outExtensions->robustResourceInitializationANGLE = true; 475 476 // EGL_KHR_image 477 outExtensions->image = true; 478 outExtensions->imageBase = true; 479 480 // EGL_ANGLE_metal_create_context_ownership_identity 481 outExtensions->metalCreateContextOwnershipIdentityANGLE = true; 482} 483 484void DisplayMtl::generateCaps(egl::Caps *outCaps) const {} 485 486void DisplayMtl::populateFeatureList(angle::FeatureList *features) 487{ 488 mFeatures.populateFeatureList(features); 489} 490 491EGLenum DisplayMtl::EGLDrawingBufferTextureTarget() 492{ 493 // TODO(anglebug.com/6395): Apple's implementation conditionalized this on 494 // MacCatalyst and whether it was running on ARM64 or X64, preferring 495 // EGL_TEXTURE_RECTANGLE_ANGLE. Metal can bind IOSurfaces to regular 2D 496 // textures, and rectangular textures don't work in the SPIR-V Metal 497 // backend, so for the time being use EGL_TEXTURE_2D on all platforms. 498 return EGL_TEXTURE_2D; 499} 500 501egl::ConfigSet DisplayMtl::generateConfigs() 502{ 503 // NOTE(hqle): generate more config permutations 504 egl::ConfigSet configs; 505 506 const gl::Version &maxVersion = getMaxSupportedESVersion(); 507 ASSERT(maxVersion >= gl::Version(2, 0)); 508 bool supportsES3 = maxVersion >= gl::Version(3, 0); 509 510 egl::Config config; 511 512 // Native stuff 513 config.nativeVisualID = 0; 514 config.nativeVisualType = 0; 515 config.nativeRenderable = EGL_TRUE; 516 517 config.colorBufferType = EGL_RGB_BUFFER; 518 config.luminanceSize = 0; 519 config.alphaMaskSize = 0; 520 521 config.transparentType = EGL_NONE; 522 523 // Pbuffer 524 config.bindToTextureTarget = EGLDrawingBufferTextureTarget(); 525 config.maxPBufferWidth = 4096; 526 config.maxPBufferHeight = 4096; 527 config.maxPBufferPixels = 4096 * 4096; 528 529 // Caveat 530 config.configCaveat = EGL_NONE; 531 532 // Misc 533 config.sampleBuffers = 0; 534 config.samples = 0; 535 config.level = 0; 536 config.bindToTextureRGB = EGL_FALSE; 537 config.bindToTextureRGBA = EGL_TRUE; 538 539 config.surfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT; 540 541#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 542 config.minSwapInterval = 0; 543 config.maxSwapInterval = 1; 544#else 545 config.minSwapInterval = 1; 546 config.maxSwapInterval = 1; 547#endif 548 549 config.renderTargetFormat = GL_RGBA8; 550 config.depthStencilFormat = GL_DEPTH24_STENCIL8; 551 552 config.conformant = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0); 553 config.renderableType = config.conformant; 554 555 config.matchNativePixmap = EGL_NONE; 556 557 config.colorComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; 558 559 constexpr int samplesSupported[] = {0, 4}; 560 561 for (int samples : samplesSupported) 562 { 563 config.samples = samples; 564 config.sampleBuffers = (samples == 0) ? 0 : 1; 565 566 // Buffer sizes 567 config.redSize = 8; 568 config.greenSize = 8; 569 config.blueSize = 8; 570 config.alphaSize = 8; 571 config.bufferSize = config.redSize + config.greenSize + config.blueSize + config.alphaSize; 572 573 // With DS 574 config.depthSize = 24; 575 config.stencilSize = 8; 576 577 configs.add(config); 578 579 // With D 580 config.depthSize = 24; 581 config.stencilSize = 0; 582 configs.add(config); 583 584 // With S 585 config.depthSize = 0; 586 config.stencilSize = 8; 587 configs.add(config); 588 589 // Tests like dEQP-GLES2.functional.depth_range.* assume EGL_DEPTH_SIZE is properly set even 590 // if renderConfig attributes are set to glu::RenderConfig::DONT_CARE 591 config.depthSize = GetDepthSize(config.depthStencilFormat); 592 config.stencilSize = GetStencilSize(config.depthStencilFormat); 593 configs.add(config); 594 } 595 596 return configs; 597} 598 599bool DisplayMtl::isValidNativeWindow(EGLNativeWindowType window) const 600{ 601 ANGLE_MTL_OBJC_SCOPE 602 { 603 NSObject *layer = (__bridge NSObject *)(window); 604 return [layer isKindOfClass:[CALayer class]]; 605 } 606} 607 608egl::Error DisplayMtl::validateClientBuffer(const egl::Config *configuration, 609 EGLenum buftype, 610 EGLClientBuffer clientBuffer, 611 const egl::AttributeMap &attribs) const 612{ 613 switch (buftype) 614 { 615 case EGL_IOSURFACE_ANGLE: 616 if (!IOSurfaceSurfaceMtl::ValidateAttributes(clientBuffer, attribs)) 617 { 618 return egl::EglBadAttribute(); 619 } 620 break; 621 default: 622 UNREACHABLE(); 623 return egl::EglBadAttribute(); 624 } 625 return egl::NoError(); 626} 627 628egl::Error DisplayMtl::validateImageClientBuffer(const gl::Context *context, 629 EGLenum target, 630 EGLClientBuffer clientBuffer, 631 const egl::AttributeMap &attribs) const 632{ 633 switch (target) 634 { 635 case EGL_METAL_TEXTURE_ANGLE: 636 if (!TextureImageSiblingMtl::ValidateClientBuffer(this, clientBuffer)) 637 { 638 return egl::EglBadAttribute(); 639 } 640 break; 641 default: 642 UNREACHABLE(); 643 return egl::EglBadAttribute(); 644 } 645 return egl::NoError(); 646} 647 648gl::Caps DisplayMtl::getNativeCaps() const 649{ 650 ensureCapsInitialized(); 651 return mNativeCaps; 652} 653const gl::TextureCapsMap &DisplayMtl::getNativeTextureCaps() const 654{ 655 ensureCapsInitialized(); 656 return mNativeTextureCaps; 657} 658const gl::Extensions &DisplayMtl::getNativeExtensions() const 659{ 660 ensureCapsInitialized(); 661 return mNativeExtensions; 662} 663 664const gl::Limitations &DisplayMtl::getNativeLimitations() const 665{ 666 ensureCapsInitialized(); 667 return mNativeLimitations; 668} 669 670void DisplayMtl::ensureCapsInitialized() const 671{ 672 if (mCapsInitialized) 673 { 674 return; 675 } 676 677 mCapsInitialized = true; 678 679 // Reset 680 mNativeCaps = gl::Caps(); 681 682 // Fill extension and texture caps 683 initializeExtensions(); 684 initializeTextureCaps(); 685 686 // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf 687 mNativeCaps.maxElementIndex = std::numeric_limits<GLuint>::max() - 1; 688 mNativeCaps.max3DTextureSize = 2048; 689#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 690 mNativeCaps.max2DTextureSize = 16384; 691 // On macOS exclude [[position]] from maxVaryingVectors. 692 mNativeCaps.maxVaryingVectors = 31 - 1; 693 mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxFragmentInputComponents = 124 - 4; 694#else 695 if (supportsAppleGPUFamily(3)) 696 { 697 mNativeCaps.max2DTextureSize = 16384; 698 mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxFragmentInputComponents = 124; 699 mNativeCaps.maxVaryingVectors = mNativeCaps.maxVertexOutputComponents / 4; 700 } 701 else 702 { 703 mNativeCaps.max2DTextureSize = 8192; 704 mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxFragmentInputComponents = 60; 705 mNativeCaps.maxVaryingVectors = mNativeCaps.maxVertexOutputComponents / 4; 706 } 707#endif 708 709 mNativeCaps.maxArrayTextureLayers = 2048; 710 mNativeCaps.maxLODBias = 2.0; // default GLES3 limit 711 mNativeCaps.maxCubeMapTextureSize = mNativeCaps.max2DTextureSize; 712 mNativeCaps.maxRenderbufferSize = mNativeCaps.max2DTextureSize; 713 mNativeCaps.minAliasedPointSize = 1; 714 // NOTE(hqle): Metal has some problems drawing big point size even though 715 // Metal-Feature-Set-Tables.pdf says that max supported point size is 511. We limit it to 64 716 // for now. http://anglebug.com/4816 717 718 // NOTE(kpiddington): This seems to be fixed in macOS Monterey 719 if (ANGLE_APPLE_AVAILABLE_XCI(12.0, 15.0, 15.0)) 720 { 721 mNativeCaps.maxAliasedPointSize = 511; 722 } 723 else 724 { 725 mNativeCaps.maxAliasedPointSize = 64; 726 } 727 mNativeCaps.minAliasedLineWidth = 1.0f; 728 mNativeCaps.maxAliasedLineWidth = 1.0f; 729 730 mNativeCaps.maxDrawBuffers = mtl::kMaxRenderTargets; 731 mNativeCaps.maxFramebufferWidth = mNativeCaps.max2DTextureSize; 732 mNativeCaps.maxFramebufferHeight = mNativeCaps.max2DTextureSize; 733 mNativeCaps.maxColorAttachments = mtl::kMaxRenderTargets; 734 mNativeCaps.maxViewportWidth = mNativeCaps.max2DTextureSize; 735 mNativeCaps.maxViewportHeight = mNativeCaps.max2DTextureSize; 736 737 // MSAA 738 mNativeCaps.maxSamples = mFormatTable.getMaxSamples(); 739 mNativeCaps.maxSampleMaskWords = 0; 740 mNativeCaps.maxColorTextureSamples = mNativeCaps.maxSamples; 741 mNativeCaps.maxDepthTextureSamples = mNativeCaps.maxSamples; 742 mNativeCaps.maxIntegerSamples = 1; 743 744 mNativeCaps.maxVertexAttributes = mtl::kMaxVertexAttribs; 745 mNativeCaps.maxVertexAttribBindings = mtl::kMaxVertexAttribs; 746 mNativeCaps.maxVertexAttribRelativeOffset = std::numeric_limits<GLint>::max(); 747 mNativeCaps.maxVertexAttribStride = std::numeric_limits<GLint>::max(); 748 749 // glGet() use signed integer as parameter so we have to use GLint's max here, not GLuint. 750 mNativeCaps.maxElementsIndices = std::numeric_limits<GLint>::max(); 751 mNativeCaps.maxElementsVertices = std::numeric_limits<GLint>::max(); 752 753 // Looks like all floats are IEEE according to the docs here: 754 mNativeCaps.vertexHighpFloat.setIEEEFloat(); 755 mNativeCaps.vertexMediumpFloat.setIEEEFloat(); 756 mNativeCaps.vertexLowpFloat.setIEEEFloat(); 757 mNativeCaps.fragmentHighpFloat.setIEEEFloat(); 758 mNativeCaps.fragmentMediumpFloat.setIEEEFloat(); 759 mNativeCaps.fragmentLowpFloat.setIEEEFloat(); 760 761 mNativeCaps.vertexHighpInt.setTwosComplementInt(32); 762 mNativeCaps.vertexMediumpInt.setTwosComplementInt(32); 763 mNativeCaps.vertexLowpInt.setTwosComplementInt(32); 764 mNativeCaps.fragmentHighpInt.setTwosComplementInt(32); 765 mNativeCaps.fragmentMediumpInt.setTwosComplementInt(32); 766 mNativeCaps.fragmentLowpInt.setTwosComplementInt(32); 767 768 GLuint maxDefaultUniformVectors = mtl::kDefaultUniformsMaxSize / (sizeof(GLfloat) * 4); 769 770 const GLuint maxDefaultUniformComponents = maxDefaultUniformVectors * 4; 771 772 // Uniforms are implemented using a uniform buffer, so the max number of uniforms we can 773 // support is the max buffer range divided by the size of a single uniform (4X float). 774 mNativeCaps.maxVertexUniformVectors = maxDefaultUniformVectors; 775 mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Vertex] = maxDefaultUniformComponents; 776 mNativeCaps.maxFragmentUniformVectors = maxDefaultUniformVectors; 777 mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Fragment] = maxDefaultUniformComponents; 778 779 mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Vertex] = mtl::kMaxShaderUBOs; 780 mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Fragment] = mtl::kMaxShaderUBOs; 781 mNativeCaps.maxCombinedUniformBlocks = mtl::kMaxGLUBOBindings; 782 783 // Note that we currently implement textures as combined image+samplers, so the limit is 784 // the minimum of supported samplers and sampled images. 785 mNativeCaps.maxCombinedTextureImageUnits = mtl::kMaxGLSamplerBindings; 786 mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment] = mtl::kMaxShaderSamplers; 787 mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex] = mtl::kMaxShaderSamplers; 788 789 // No info from Metal given, use default GLES3 spec values: 790 mNativeCaps.minProgramTexelOffset = -8; 791 mNativeCaps.maxProgramTexelOffset = 7; 792 793 // NOTE(hqle): support storage buffer. 794 const uint32_t maxPerStageStorageBuffers = 0; 795 mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] = maxPerStageStorageBuffers; 796 mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] = maxPerStageStorageBuffers; 797 mNativeCaps.maxCombinedShaderStorageBlocks = maxPerStageStorageBuffers; 798 799 // Fill in additional limits for UBOs and SSBOs. 800 mNativeCaps.maxUniformBufferBindings = mNativeCaps.maxCombinedUniformBlocks; 801 mNativeCaps.maxUniformBlockSize = mtl::kMaxUBOSize; // Default according to GLES 3.0 spec. 802 if (supportsAppleGPUFamily(1)) 803 { 804 mNativeCaps.uniformBufferOffsetAlignment = 805 16; // on Apple based GPU's We can ignore data types when setting constant buffer 806 // alignment at 16. 807 } 808 else 809 { 810 mNativeCaps.uniformBufferOffsetAlignment = 811 256; // constant buffers on all other GPUs must be aligned to 256. 812 } 813 814 mNativeCaps.maxShaderStorageBufferBindings = 0; 815 mNativeCaps.maxShaderStorageBlockSize = 0; 816 mNativeCaps.shaderStorageBufferOffsetAlignment = 0; 817 818 // UBO plus default uniform limits 819 const uint32_t maxCombinedUniformComponents = 820 maxDefaultUniformComponents + mtl::kMaxUBOSize * mtl::kMaxShaderUBOs / 4; 821 for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes) 822 { 823 mNativeCaps.maxCombinedShaderUniformComponents[shaderType] = maxCombinedUniformComponents; 824 } 825 826 mNativeCaps.maxCombinedShaderOutputResources = 0; 827 828 mNativeCaps.maxTransformFeedbackInterleavedComponents = 829 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; 830 mNativeCaps.maxTransformFeedbackSeparateAttributes = 831 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS; 832 mNativeCaps.maxTransformFeedbackSeparateComponents = 833 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS; 834 835 // GL_OES_get_program_binary 836 mNativeCaps.programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); 837 838 // GL_APPLE_clip_distance 839 mNativeCaps.maxClipDistances = mFeatures.directMetalGeneration.enabled ? 0 : 8; 840 841 // Metal doesn't support GL_TEXTURE_COMPARE_MODE=GL_NONE for shadow samplers 842 mNativeLimitations.noShadowSamplerCompareModeNone = true; 843 844 // Apple platforms require PVRTC1 textures to be squares. 845 mNativeLimitations.squarePvrtc1 = true; 846 847 // Older Metal does not support compressed formats for TEXTURE_3D target. 848 if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0)) 849 { 850 mNativeLimitations.noCompressedTexture3D = !supportsEitherGPUFamily(3, 1); 851 } 852 else 853 { 854 mNativeLimitations.noCompressedTexture3D = true; 855 } 856 857 // Direct-to-metal constants: 858 mNativeCaps.driverUniformsBindingIndex = mtl::kDriverUniformsBindingIndex; 859 mNativeCaps.defaultUniformsBindingIndex = mtl::kDefaultUniformsBindingIndex; 860 mNativeCaps.UBOArgumentBufferBindingIndex = mtl::kUBOArgumentBufferBindingIndex; 861} 862 863void DisplayMtl::initializeExtensions() const 864{ 865 // Reset 866 mNativeExtensions = gl::Extensions(); 867 868 // Enable this for simple buffer readback testing, but some functionality is missing. 869 // NOTE(hqle): Support full mapBufferRangeEXT extension. 870 mNativeExtensions.mapbufferOES = true; 871 mNativeExtensions.mapBufferRangeEXT = true; 872 mNativeExtensions.textureStorageEXT = true; 873 mNativeExtensions.drawBuffersEXT = true; 874 mNativeExtensions.drawBuffersIndexedEXT = true; 875 mNativeExtensions.drawBuffersIndexedOES = true; 876 mNativeExtensions.fboRenderMipmapOES = true; 877 mNativeExtensions.fragDepthEXT = true; 878 mNativeExtensions.framebufferBlitANGLE = true; 879 mNativeExtensions.framebufferBlitNV = true; 880 mNativeExtensions.framebufferMultisampleANGLE = true; 881 mNativeExtensions.copyTextureCHROMIUM = true; 882 mNativeExtensions.copyCompressedTextureCHROMIUM = false; 883 884 // EXT_debug_marker is not implemented yet, but the entry points must be exposed for the 885 // Metal backend to be used in Chrome (http://anglebug.com/4946) 886 mNativeExtensions.debugMarkerEXT = true; 887 888 mNativeExtensions.robustnessEXT = true; 889 mNativeExtensions.textureBorderClampOES = false; // not implemented yet 890 mNativeExtensions.multiDrawIndirectEXT = true; 891 mNativeExtensions.translatedShaderSourceANGLE = true; 892 mNativeExtensions.discardFramebufferEXT = true; 893 // TODO(anglebug.com/6395): Apple's implementation exposed 894 // mNativeExtensions.textureRectangle = true here and 895 // EGL_TEXTURE_RECTANGLE_ANGLE as the eglBindTexImage texture target on 896 // macOS. This no longer seems necessary as IOSurfaces can be bound to 897 // regular 2D textures with Metal, and causes other problems such as 898 // breaking the SPIR-V Metal compiler. 899 900 // TODO(anglebug.com/6395): figure out why WebGL drawing buffer 901 // creation fails on macOS when the Metal backend advertises the 902 // EXT_multisampled_render_to_texture extension. 903#if !defined(ANGLE_PLATFORM_MACOS) 904 // EXT_multisampled_render_to_texture 905 if (mFeatures.allowMultisampleStoreAndResolve.enabled && 906 mFeatures.hasDepthAutoResolve.enabled && mFeatures.hasStencilAutoResolve.enabled) 907 { 908 mNativeExtensions.multisampledRenderToTextureEXT = true; 909 } 910#endif 911 912 // Enable EXT_blend_minmax 913 mNativeExtensions.blendMinmaxEXT = true; 914 915 mNativeExtensions.EGLImageOES = true; 916 mNativeExtensions.EGLImageExternalOES = false; 917 // NOTE(hqle): Support GL_OES_EGL_image_external_essl3. 918 mNativeExtensions.EGLImageExternalEssl3OES = false; 919 920 mNativeExtensions.memoryObjectEXT = false; 921 mNativeExtensions.memoryObjectFdEXT = false; 922 923 mNativeExtensions.semaphoreEXT = false; 924 mNativeExtensions.semaphoreFdEXT = false; 925 926 mNativeExtensions.instancedArraysANGLE = true; 927 mNativeExtensions.instancedArraysEXT = mNativeExtensions.instancedArraysANGLE; 928 929 mNativeExtensions.robustBufferAccessBehaviorKHR = false; 930 931 mNativeExtensions.EGLSyncOES = false; 932 933 mNativeExtensions.occlusionQueryBooleanEXT = true; 934 935 mNativeExtensions.disjointTimerQueryEXT = false; 936 mNativeCaps.queryCounterBitsTimeElapsed = 0; 937 mNativeCaps.queryCounterBitsTimestamp = 0; 938 939 mNativeExtensions.textureFilterAnisotropicEXT = true; 940 mNativeCaps.maxTextureAnisotropy = 16; 941 942 mNativeExtensions.textureNpotOES = true; 943 944 mNativeExtensions.texture3DOES = true; 945 946 mNativeExtensions.shaderTextureLodEXT = true; 947 948 mNativeExtensions.standardDerivativesOES = true; 949 950 mNativeExtensions.elementIndexUintOES = true; 951 952 // GL_OES_get_program_binary 953 mNativeExtensions.getProgramBinaryOES = true; 954 955 // GL_APPLE_clip_distance 956 mNativeExtensions.clipDistanceAPPLE = !mFeatures.directMetalGeneration.enabled; 957 958 // GL_NV_pixel_buffer_object 959 mNativeExtensions.pixelBufferObjectNV = true; 960 961 if (mFeatures.hasEvents.enabled) 962 { 963 // MTLSharedEvent is only available since Metal 2.1 964 965 // GL_NV_fence 966 mNativeExtensions.fenceNV = true; 967 968 // GL_OES_EGL_sync 969 mNativeExtensions.EGLSyncOES = true; 970 971 // GL_ARB_sync 972 mNativeExtensions.syncARB = true; 973 } 974 975 // GL_KHR_parallel_shader_compile 976 mNativeExtensions.parallelShaderCompileKHR = true; 977 978 mNativeExtensions.baseVertexBaseInstanceANGLE = mFeatures.hasBaseVertexInstancedDraw.enabled; 979 mNativeExtensions.baseVertexBaseInstanceShaderBuiltinANGLE = 980 mFeatures.hasBaseVertexInstancedDraw.enabled; 981} 982 983void DisplayMtl::initializeTextureCaps() const 984{ 985 mNativeTextureCaps.clear(); 986 987 mFormatTable.generateTextureCaps(this, &mNativeTextureCaps, 988 &mNativeCaps.compressedTextureFormats); 989 990 // Re-verify texture extensions. 991 mNativeExtensions.setTextureExtensionSupport(mNativeTextureCaps); 992 993 // When ETC2/EAC formats are natively supported, enable ANGLE-specific extension string to 994 // expose them to WebGL. In other case, mark potentially-available ETC1 extension as 995 // emulated. 996 if (supportsAppleGPUFamily(1) && gl::DetermineCompressedTextureETCSupport(mNativeTextureCaps)) 997 { 998 mNativeExtensions.compressedTextureEtcANGLE = true; 999 } 1000 else 1001 { 1002 mNativeLimitations.emulatedEtc1 = true; 1003 } 1004 1005 // Enable ASTC sliced 3D, requires MTLGPUFamilyApple3 1006 if (supportsAppleGPUFamily(3) && mNativeExtensions.textureCompressionAstcLdrKHR) 1007 { 1008 mNativeExtensions.textureCompressionAstcSliced3dKHR = true; 1009 } 1010 1011 // Enable ASTC HDR, requires MTLGPUFamilyApple6 1012 if (supportsAppleGPUFamily(6) && mNativeExtensions.textureCompressionAstcLdrKHR) 1013 { 1014 mNativeExtensions.textureCompressionAstcHdrKHR = true; 1015 } 1016 1017 // Disable all depth buffer and stencil buffer readback extensions until we need them 1018 mNativeExtensions.readDepthNV = false; 1019 mNativeExtensions.readStencilNV = false; 1020 mNativeExtensions.depthBufferFloat2NV = false; 1021} 1022 1023void DisplayMtl::initializeLimitations() 1024{ 1025 mNativeLimitations.noVertexAttributeAliasing = true; 1026} 1027 1028void DisplayMtl::initializeFeatures() 1029{ 1030 bool isMetal2_1 = false; 1031 bool isMetal2_2 = false; 1032 if (ANGLE_APPLE_AVAILABLE_XCI(10.14, 13.0, 12.0)) 1033 { 1034 isMetal2_1 = true; 1035 } 1036 1037 if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0)) 1038 { 1039 isMetal2_2 = true; 1040 } 1041 1042 bool isOSX = TARGET_OS_OSX; 1043 bool isCatalyst = TARGET_OS_MACCATALYST; 1044 bool isSimulator = TARGET_OS_SIMULATOR; 1045 bool isARM = ANGLE_MTL_ARM; 1046 1047 ANGLE_FEATURE_CONDITION((&mFeatures), allowGenMultipleMipsPerPass, true); 1048 ANGLE_FEATURE_CONDITION((&mFeatures), forceBufferGPUStorage, false); 1049 ANGLE_FEATURE_CONDITION((&mFeatures), hasExplicitMemBarrier, 1050 isMetal2_1 && (isOSX || isCatalyst) && !isARM); 1051 ANGLE_FEATURE_CONDITION((&mFeatures), hasDepthAutoResolve, supportsEitherGPUFamily(3, 2)); 1052 ANGLE_FEATURE_CONDITION((&mFeatures), hasStencilAutoResolve, supportsEitherGPUFamily(5, 2)); 1053 ANGLE_FEATURE_CONDITION((&mFeatures), allowMultisampleStoreAndResolve, 1054 supportsEitherGPUFamily(3, 1)); 1055 1056 ANGLE_FEATURE_CONDITION((&mFeatures), allowRuntimeSamplerCompareMode, 1057 supportsEitherGPUFamily(3, 1)); 1058 // AMD does not support sample_compare_grad 1059 ANGLE_FEATURE_CONDITION((&mFeatures), allowSamplerCompareGradient, 1060 supportsEitherGPUFamily(3, 1) && !isAMD()); 1061 ANGLE_FEATURE_CONDITION((&mFeatures), allowSamplerCompareLod, supportsEitherGPUFamily(3, 1)); 1062 1063 // http://anglebug.com/4919 1064 // Stencil blit shader is not compiled on Intel & NVIDIA, need investigation. 1065 ANGLE_FEATURE_CONDITION((&mFeatures), hasShaderStencilOutput, 1066 isMetal2_1 && !isIntel() && !isNVIDIA()); 1067 1068 ANGLE_FEATURE_CONDITION((&mFeatures), hasTextureSwizzle, 1069 isMetal2_2 && supportsEitherGPUFamily(3, 2) && !isSimulator); 1070 1071 // http://crbug.com/1136673 1072 // Fence sync is flaky on Nvidia 1073 ANGLE_FEATURE_CONDITION((&mFeatures), hasEvents, isMetal2_1 && !isNVIDIA()); 1074 1075 ANGLE_FEATURE_CONDITION((&mFeatures), hasCheapRenderPass, (isOSX || isCatalyst) && !isARM); 1076 1077 // http://anglebug.com/5235 1078 // D24S8 is unreliable on AMD. 1079 ANGLE_FEATURE_CONDITION((&mFeatures), forceD24S8AsUnsupported, isAMD()); 1080 1081 // Base Vertex drawing is only supported since GPU family 3. 1082 ANGLE_FEATURE_CONDITION((&mFeatures), hasBaseVertexInstancedDraw, 1083 isOSX || isCatalyst || supportsAppleGPUFamily(3)); 1084 1085 ANGLE_FEATURE_CONDITION((&mFeatures), hasNonUniformDispatch, 1086 isOSX || isCatalyst || supportsAppleGPUFamily(4)); 1087 1088 ANGLE_FEATURE_CONDITION((&mFeatures), allowSeparateDepthStencilBuffers, 1089 !isOSX && !isCatalyst && !isSimulator); 1090 ANGLE_FEATURE_CONDITION((&mFeatures), rewriteRowMajorMatrices, true); 1091 ANGLE_FEATURE_CONDITION((&mFeatures), emulateTransformFeedback, true); 1092 1093 ANGLE_FEATURE_CONDITION((&mFeatures), intelExplicitBoolCastWorkaround, 1094 isIntel() && GetMacOSVersion() < OSVersion(11, 0, 0)); 1095 ANGLE_FEATURE_CONDITION((&mFeatures), intelDisableFastMath, 1096 isIntel() && GetMacOSVersion() < OSVersion(12, 0, 0)); 1097 1098 ANGLE_FEATURE_CONDITION((&mFeatures), multisampleColorFormatShaderReadWorkaround, isAMD()); 1099 ANGLE_FEATURE_CONDITION((&mFeatures), copyIOSurfaceToNonIOSurfaceForReadOptimization, 1100 isIntel()); 1101 1102 ANGLE_FEATURE_CONDITION((&mFeatures), forceNonCSBaseMipmapGeneration, isIntel()); 1103 1104 bool defaultDirectToMetal = true; 1105 1106 ANGLE_FEATURE_CONDITION((&mFeatures), directMetalGeneration, defaultDirectToMetal); 1107 1108 ApplyFeatureOverrides(&mFeatures, getState()); 1109#ifdef ANGLE_ENABLE_ASSERTS 1110 fprintf(stderr, "Shader compiler output: %s\n", 1111 mFeatures.directMetalGeneration.enabled ? "Metal" : "SPIR-V"); 1112#endif 1113} 1114 1115angle::Result DisplayMtl::initializeShaderLibrary() 1116{ 1117#ifdef ANGLE_METAL_XCODE_BUILDS_SHADERS 1118 mDefaultShadersAsyncInfo.reset(new DefaultShaderAsyncInfoMtl); 1119 1120 const uint8_t *compiled_shader_binary; 1121 size_t compiled_shader_binary_len; 1122 compiled_shader_binary = gMetalBinaryShaders; 1123 compiled_shader_binary_len = gMetalBinaryShaders_len; 1124 mtl::AutoObjCPtr<NSError *> err = nil; 1125 mtl::AutoObjCPtr<id<MTLLibrary>> mDefaultShaders = mtl::CreateShaderLibraryFromBinary( 1126 getMetalDevice(), compiled_shader_binary, compiled_shader_binary_len, &err); 1127 mDefaultShadersAsyncInfo->defaultShaders = std::move(mDefaultShaders.get()); 1128 mDefaultShadersAsyncInfo->defaultShadersCompileError = std::move(err.get()); 1129 mDefaultShadersAsyncInfo->compiled = true; 1130 1131#else 1132 mDefaultShadersAsyncInfo.reset(new DefaultShaderAsyncInfoMtl); 1133 1134 // Create references to async info struct since it might be released in terminate(), but the 1135 // callback might still not be fired yet. 1136 std::shared_ptr<DefaultShaderAsyncInfoMtl> asyncRef = mDefaultShadersAsyncInfo; 1137 1138 // Compile the default shaders asynchronously 1139 ANGLE_MTL_OBJC_SCOPE 1140 { 1141 auto nsSource = [[NSString alloc] initWithBytesNoCopy:gDefaultMetallibSrc 1142 length:sizeof(gDefaultMetallibSrc) 1143 encoding:NSUTF8StringEncoding 1144 freeWhenDone:NO]; 1145 auto options = [[[MTLCompileOptions alloc] init] ANGLE_MTL_AUTORELEASE]; 1146 [getMetalDevice() newLibraryWithSource:nsSource 1147 options:options 1148 completionHandler:^(id<MTLLibrary> library, NSError *error) { 1149 std::unique_lock<std::mutex> lg(asyncRef->lock); 1150 1151 asyncRef->defaultShaders = std::move(library); 1152 asyncRef->defaultShadersCompileError = std::move(error); 1153 1154 asyncRef->compiled = true; 1155 asyncRef->cv.notify_one(); 1156 }]; 1157 1158 [nsSource ANGLE_MTL_AUTORELEASE]; 1159 } 1160#endif 1161 return angle::Result::Continue; 1162} 1163 1164id<MTLLibrary> DisplayMtl::getDefaultShadersLib() 1165{ 1166 std::unique_lock<std::mutex> lg(mDefaultShadersAsyncInfo->lock); 1167 if (!mDefaultShadersAsyncInfo->compiled) 1168 { 1169 // Wait for async compilation 1170 mDefaultShadersAsyncInfo->cv.wait(lg, 1171 [this] { return mDefaultShadersAsyncInfo->compiled; }); 1172 } 1173 1174 if (mDefaultShadersAsyncInfo->defaultShadersCompileError && 1175 !mDefaultShadersAsyncInfo->defaultShaders) 1176 { 1177 ANGLE_MTL_OBJC_SCOPE 1178 { 1179 ERR() << "Internal error: " 1180 << mDefaultShadersAsyncInfo->defaultShadersCompileError.get() 1181 .localizedDescription.UTF8String; 1182 } 1183 // This is not supposed to happen 1184 UNREACHABLE(); 1185 } 1186 1187 return mDefaultShadersAsyncInfo->defaultShaders; 1188} 1189 1190bool DisplayMtl::supportsAppleGPUFamily(uint8_t iOSFamily) const 1191{ 1192 return mtl::SupportsAppleGPUFamily(getMetalDevice(), iOSFamily); 1193} 1194 1195bool DisplayMtl::supportsMacGPUFamily(uint8_t macFamily) const 1196{ 1197 return mtl::SupportsMacGPUFamily(getMetalDevice(), macFamily); 1198} 1199 1200bool DisplayMtl::supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) const 1201{ 1202 return supportsAppleGPUFamily(iOSFamily) || supportsMacGPUFamily(macFamily); 1203} 1204 1205bool DisplayMtl::supports32BitFloatFiltering() const 1206{ 1207#if (defined(__MAC_11_0) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_11_0) || \ 1208 (defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_14_0) || \ 1209 (defined(__TVOS_14_0) && __TV_OS_VERSION_MIN_REQUIRED >= __TVOS_14_0) 1210 if (@available(ios 14.0, macOS 11.0, *)) 1211 { 1212 return [mMetalDevice supports32BitFloatFiltering]; 1213 } 1214 else 1215#endif 1216 { 1217 return supportsMacGPUFamily(1); 1218 } 1219} 1220 1221bool DisplayMtl::supportsDepth24Stencil8PixelFormat() const 1222{ 1223#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 1224 return [mMetalDevice isDepth24Stencil8PixelFormatSupported]; 1225#else 1226 return false; 1227#endif 1228} 1229bool DisplayMtl::isAMD() const 1230{ 1231 return angle::IsAMD(mMetalDeviceVendorId); 1232} 1233 1234bool DisplayMtl::isIntel() const 1235{ 1236 return angle::IsIntel(mMetalDeviceVendorId); 1237} 1238 1239bool DisplayMtl::isNVIDIA() const 1240{ 1241 return angle::IsNVIDIA(mMetalDeviceVendorId); 1242} 1243 1244bool DisplayMtl::isSimulator() const 1245{ 1246 return TARGET_OS_SIMULATOR; 1247} 1248 1249#if ANGLE_MTL_EVENT_AVAILABLE 1250mtl::AutoObjCObj<MTLSharedEventListener> DisplayMtl::getOrCreateSharedEventListener() 1251{ 1252 if (!mSharedEventListener) 1253 { 1254 ANGLE_MTL_OBJC_SCOPE 1255 { 1256 mSharedEventListener = [[[MTLSharedEventListener alloc] init] ANGLE_MTL_AUTORELEASE]; 1257 ASSERT(mSharedEventListener); // Failure here most probably means a sandbox issue. 1258 } 1259 } 1260 return mSharedEventListener; 1261} 1262#endif 1263 1264bool DisplayMtl::useDirectToMetalCompiler() const 1265{ 1266 return mFeatures.directMetalGeneration.enabled; 1267} 1268 1269} // namespace rx 1270