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#include <sys/param.h> 11 12#include "common/apple_platform_utils.h" 13#include "common/system_utils.h" 14#include "gpu_info_util/SystemInfo.h" 15#include "libANGLE/Context.h" 16#include "libANGLE/Display.h" 17#include "libANGLE/Surface.h" 18#include "libANGLE/renderer/driver_utils.h" 19#include "libANGLE/renderer/metal/CompilerMtl.h" 20#include "libANGLE/renderer/metal/ContextMtl.h" 21#include "libANGLE/renderer/metal/DeviceMtl.h" 22#include "libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h" 23#include "libANGLE/renderer/metal/ImageMtl.h" 24#include "libANGLE/renderer/metal/SurfaceMtl.h" 25#include "libANGLE/renderer/metal/SyncMtl.h" 26#include "libANGLE/renderer/metal/mtl_common.h" 27#include "libANGLE/trace.h" 28#include "mtl_command_buffer.h" 29#include "platform/PlatformMethods.h" 30 31#if ANGLE_METAL_XCODE_BUILDS_SHADERS 32# include "libANGLE/renderer/metal/shaders/mtl_internal_shaders_metallib.h" 33#elif ANGLE_METAL_HAS_PREBUILT_INTERNAL_SHADERS 34# include "mtl_internal_shaders_metallib.h" 35#else 36# include "libANGLE/renderer/metal/shaders/mtl_internal_shaders_src_autogen.h" 37#endif 38 39#include "EGL/eglext.h" 40 41namespace rx 42{ 43 44static EGLint GetDepthSize(GLint internalformat) 45{ 46 switch (internalformat) 47 { 48 case GL_STENCIL_INDEX8: 49 return 0; 50 case GL_DEPTH_COMPONENT16: 51 return 16; 52 case GL_DEPTH_COMPONENT24: 53 return 24; 54 case GL_DEPTH_COMPONENT32_OES: 55 return 32; 56 case GL_DEPTH_COMPONENT32F: 57 return 32; 58 case GL_DEPTH24_STENCIL8: 59 return 24; 60 case GL_DEPTH32F_STENCIL8: 61 return 32; 62 default: 63 // UNREACHABLE(internalformat); 64 return 0; 65 } 66} 67 68static EGLint GetStencilSize(GLint internalformat) 69{ 70 switch (internalformat) 71 { 72 case GL_STENCIL_INDEX8: 73 return 8; 74 case GL_DEPTH_COMPONENT16: 75 return 0; 76 case GL_DEPTH_COMPONENT24: 77 return 0; 78 case GL_DEPTH_COMPONENT32_OES: 79 return 0; 80 case GL_DEPTH_COMPONENT32F: 81 return 0; 82 case GL_DEPTH24_STENCIL8: 83 return 8; 84 case GL_DEPTH32F_STENCIL8: 85 return 8; 86 default: 87 // UNREACHABLE(internalformat); 88 return 0; 89 } 90} 91 92bool IsMetalDisplayAvailable() 93{ 94 return angle::IsMetalRendererAvailable(); 95} 96 97DisplayImpl *CreateMetalDisplay(const egl::DisplayState &state) 98{ 99 return new DisplayMtl(state); 100} 101 102DisplayMtl::DisplayMtl(const egl::DisplayState &state) 103 : DisplayImpl(state), mDisplay(nullptr), mStateCache(mFeatures) 104{} 105 106DisplayMtl::~DisplayMtl() {} 107 108egl::Error DisplayMtl::initialize(egl::Display *display) 109{ 110 ASSERT(IsMetalDisplayAvailable()); 111 112 angle::Result result = initializeImpl(display); 113 if (result != angle::Result::Continue) 114 { 115 terminate(); 116 return egl::EglNotInitialized(); 117 } 118 return egl::NoError(); 119} 120 121angle::Result DisplayMtl::initializeImpl(egl::Display *display) 122{ 123 ANGLE_MTL_OBJC_SCOPE 124 { 125 mDisplay = display; 126 127 mMetalDevice = getMetalDeviceMatchingAttribute(display->getAttributeMap()); 128 // If we can't create a device, fail initialization. 129 if (!mMetalDevice.get()) 130 { 131 return angle::Result::Stop; 132 } 133 134 mMetalDeviceVendorId = mtl::GetDeviceVendorId(mMetalDevice); 135 136 mCapsInitialized = false; 137 138 initializeFeatures(); 139 140 if (mFeatures.requireGpuFamily2.enabled && !supportsEitherGPUFamily(1, 2)) 141 { 142 ANGLE_MTL_LOG("Could not initialize: Metal device does not support Mac GPU family 2."); 143 return angle::Result::Stop; 144 } 145 146 if (mFeatures.disableMetalOnNvidia.enabled && isNVIDIA()) 147 { 148 ANGLE_MTL_LOG("Could not initialize: Metal not supported on NVIDIA GPUs."); 149 return angle::Result::Stop; 150 } 151 152 mCmdQueue.set([[mMetalDevice newCommandQueue] ANGLE_MTL_AUTORELEASE]); 153 154 ANGLE_TRY(mFormatTable.initialize(this)); 155 ANGLE_TRY(initializeShaderLibrary()); 156 157 mUtils = std::make_unique<mtl::RenderUtils>(this); 158 159 return angle::Result::Continue; 160 } 161} 162 163void DisplayMtl::terminate() 164{ 165 mUtils = nullptr; 166 mCmdQueue.reset(); 167 mDefaultShaders = nil; 168 mMetalDevice = nil; 169 mSharedEventListener = nil; 170 mCapsInitialized = false; 171 172 mMetalDeviceVendorId = 0; 173 mComputedAMDBronze = false; 174 mIsAMDBronze = false; 175} 176 177bool DisplayMtl::testDeviceLost() 178{ 179 return false; 180} 181 182egl::Error DisplayMtl::restoreLostDevice(const egl::Display *display) 183{ 184 return egl::NoError(); 185} 186 187std::string DisplayMtl::getRendererDescription() 188{ 189 ANGLE_MTL_OBJC_SCOPE 190 { 191 std::string desc = "ANGLE Metal Renderer"; 192 193 if (mMetalDevice) 194 { 195 desc += ": "; 196 desc += mMetalDevice.get().name.UTF8String; 197 } 198 199 return desc; 200 } 201} 202 203std::string DisplayMtl::getVendorString() 204{ 205 return GetVendorString(mMetalDeviceVendorId); 206} 207 208std::string DisplayMtl::getVersionString(bool includeFullVersion) 209{ 210 if (!includeFullVersion) 211 { 212 // For WebGL contexts it's inappropriate to include any 213 // additional version information, but Chrome requires 214 // something to be present here. 215 return "Unspecified Version"; 216 } 217 218 ANGLE_MTL_OBJC_SCOPE 219 { 220 NSProcessInfo *procInfo = [NSProcessInfo processInfo]; 221 return procInfo.operatingSystemVersionString.UTF8String; 222 } 223} 224 225DeviceImpl *DisplayMtl::createDevice() 226{ 227 return new DeviceMtl(); 228} 229 230mtl::AutoObjCPtr<id<MTLDevice>> DisplayMtl::getMetalDeviceMatchingAttribute( 231 const egl::AttributeMap &attribs) 232{ 233#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 234 auto deviceList = mtl::adoptObjCObj(MTLCopyAllDevices()); 235 236 EGLAttrib high = attribs.get(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE, 0); 237 EGLAttrib low = attribs.get(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE, 0); 238 uint64_t deviceId = 239 angle::GetSystemDeviceIdFromParts(static_cast<uint32_t>(high), static_cast<uint32_t>(low)); 240 // Check EGL_ANGLE_platform_angle_device_id to see if a device was specified. 241 if (deviceId != 0) 242 { 243 for (id<MTLDevice> device in deviceList.get()) 244 { 245 if ([device registryID] == deviceId) 246 { 247 return device; 248 } 249 } 250 } 251 252 auto externalGPUs = 253 mtl::adoptObjCObj<NSMutableArray<id<MTLDevice>>>([[NSMutableArray alloc] init]); 254 auto integratedGPUs = 255 mtl::adoptObjCObj<NSMutableArray<id<MTLDevice>>>([[NSMutableArray alloc] init]); 256 auto discreteGPUs = 257 mtl::adoptObjCObj<NSMutableArray<id<MTLDevice>>>([[NSMutableArray alloc] init]); 258 for (id<MTLDevice> device in deviceList.get()) 259 { 260 if (device.removable) 261 { 262 [externalGPUs addObject:device]; 263 } 264 else if (device.lowPower) 265 { 266 [integratedGPUs addObject:device]; 267 } 268 else 269 { 270 [discreteGPUs addObject:device]; 271 } 272 } 273 // TODO(kpiddington: External GPU support. Do we prefer high power / low bandwidth for general 274 // WebGL applications? 275 // Can we support hot-swapping in GPU's? 276 if (attribs.get(EGL_POWER_PREFERENCE_ANGLE, 0) == EGL_HIGH_POWER_ANGLE) 277 { 278 // Search for a discrete GPU first. 279 for (id<MTLDevice> device in discreteGPUs.get()) 280 { 281 if (![device isHeadless]) 282 return device; 283 } 284 } 285 else if (attribs.get(EGL_POWER_PREFERENCE_ANGLE, 0) == EGL_LOW_POWER_ANGLE) 286 { 287 // If we've selected a low power device, look through integrated devices. 288 for (id<MTLDevice> device in integratedGPUs.get()) 289 { 290 if (![device isHeadless]) 291 return device; 292 } 293 } 294 295 const std::string preferredDeviceString = angle::GetPreferredDeviceString(); 296 if (!preferredDeviceString.empty()) 297 { 298 for (id<MTLDevice> device in deviceList.get()) 299 { 300 if ([device.name.lowercaseString 301 containsString:[NSString stringWithUTF8String:preferredDeviceString.c_str()]]) 302 { 303 NSLog(@"Using Metal Device: %@", [device name]); 304 return device; 305 } 306 } 307 } 308 309#endif 310 // If we can't find anything, or are on a platform that doesn't support power options, create a 311 // default device. 312 return mtl::adoptObjCObj(MTLCreateSystemDefaultDevice()); 313} 314 315egl::Error DisplayMtl::waitClient(const gl::Context *context) 316{ 317 auto contextMtl = GetImplAs<ContextMtl>(context); 318 angle::Result result = contextMtl->finishCommandBuffer(); 319 320 if (result != angle::Result::Continue) 321 { 322 return egl::EglBadAccess(); 323 } 324 return egl::NoError(); 325} 326 327egl::Error DisplayMtl::waitNative(const gl::Context *context, EGLint engine) 328{ 329 UNIMPLEMENTED(); 330 return egl::NoError(); 331} 332 333egl::Error DisplayMtl::waitUntilWorkScheduled() 334{ 335 for (auto context : mState.contextMap) 336 { 337 auto contextMtl = GetImplAs<ContextMtl>(context.second); 338 contextMtl->flushCommandBuffer(mtl::WaitUntilScheduled); 339 } 340 return egl::NoError(); 341} 342 343SurfaceImpl *DisplayMtl::createWindowSurface(const egl::SurfaceState &state, 344 EGLNativeWindowType window, 345 const egl::AttributeMap &attribs) 346{ 347 return new WindowSurfaceMtl(this, state, window, attribs); 348} 349 350SurfaceImpl *DisplayMtl::createPbufferSurface(const egl::SurfaceState &state, 351 const egl::AttributeMap &attribs) 352{ 353 return new PBufferSurfaceMtl(this, state, attribs); 354} 355 356SurfaceImpl *DisplayMtl::createPbufferFromClientBuffer(const egl::SurfaceState &state, 357 EGLenum buftype, 358 EGLClientBuffer clientBuffer, 359 const egl::AttributeMap &attribs) 360{ 361 switch (buftype) 362 { 363 case EGL_IOSURFACE_ANGLE: 364 return new IOSurfaceSurfaceMtl(this, state, clientBuffer, attribs); 365 default: 366 UNREACHABLE(); 367 } 368 return nullptr; 369} 370 371SurfaceImpl *DisplayMtl::createPixmapSurface(const egl::SurfaceState &state, 372 NativePixmapType nativePixmap, 373 const egl::AttributeMap &attribs) 374{ 375 UNIMPLEMENTED(); 376 return static_cast<SurfaceImpl *>(0); 377} 378 379ImageImpl *DisplayMtl::createImage(const egl::ImageState &state, 380 const gl::Context *context, 381 EGLenum target, 382 const egl::AttributeMap &attribs) 383{ 384 return new ImageMtl(state, context); 385} 386 387rx::ContextImpl *DisplayMtl::createContext(const gl::State &state, 388 gl::ErrorSet *errorSet, 389 const egl::Config *configuration, 390 const gl::Context *shareContext, 391 const egl::AttributeMap &attribs) 392{ 393 return new ContextMtl(state, errorSet, attribs, this); 394} 395 396StreamProducerImpl *DisplayMtl::createStreamProducerD3DTexture( 397 egl::Stream::ConsumerType consumerType, 398 const egl::AttributeMap &attribs) 399{ 400 UNIMPLEMENTED(); 401 return nullptr; 402} 403 404ShareGroupImpl *DisplayMtl::createShareGroup(const egl::ShareGroupState &state) 405{ 406 return new ShareGroupMtl(state); 407} 408 409ExternalImageSiblingImpl *DisplayMtl::createExternalImageSibling(const gl::Context *context, 410 EGLenum target, 411 EGLClientBuffer buffer, 412 const egl::AttributeMap &attribs) 413{ 414 switch (target) 415 { 416 case EGL_METAL_TEXTURE_ANGLE: 417 return new TextureImageSiblingMtl(buffer, attribs); 418 419 default: 420 UNREACHABLE(); 421 return nullptr; 422 } 423} 424 425gl::Version DisplayMtl::getMaxSupportedESVersion() const 426{ 427#if TARGET_OS_SIMULATOR 428 // Simulator should be able to support ES3, despite not supporting iOS GPU 429 // Family 3 in its entirety. 430 // FIXME: None of the feature conditions are checked for simulator support. 431 return gl::Version(3, 0); 432#else 433 if (supportsEitherGPUFamily(3, 1)) 434 { 435 return mtl::kMaxSupportedGLVersion; 436 } 437 return gl::Version(2, 0); 438#endif 439} 440 441gl::Version DisplayMtl::getMaxConformantESVersion() const 442{ 443 return std::min(getMaxSupportedESVersion(), gl::Version(3, 0)); 444} 445 446EGLSyncImpl *DisplayMtl::createSync() 447{ 448 return new EGLSyncMtl(); 449} 450 451egl::Error DisplayMtl::makeCurrent(egl::Display *display, 452 egl::Surface *drawSurface, 453 egl::Surface *readSurface, 454 gl::Context *context) 455{ 456 if (!context) 457 { 458 return egl::NoError(); 459 } 460 461 return egl::NoError(); 462} 463 464void DisplayMtl::generateExtensions(egl::DisplayExtensions *outExtensions) const 465{ 466 outExtensions->iosurfaceClientBuffer = true; 467 outExtensions->surfacelessContext = true; 468 outExtensions->noConfigContext = true; 469 outExtensions->displayTextureShareGroup = true; 470 outExtensions->displaySemaphoreShareGroup = true; 471 outExtensions->mtlTextureClientBuffer = true; 472 outExtensions->waitUntilWorkScheduled = true; 473 474 if (mFeatures.hasEvents.enabled) 475 { 476 // MTLSharedEvent is only available since Metal 2.1 477 outExtensions->fenceSync = true; 478 outExtensions->waitSync = true; 479 } 480 481 // Note that robust resource initialization is not yet implemented. We only expose 482 // this extension so that ANGLE can be initialized in Chrome. WebGL will fail to use 483 // this extension (anglebug.com/42263503) 484 outExtensions->robustResourceInitializationANGLE = true; 485 486 // EGL_KHR_image 487 outExtensions->image = true; 488 outExtensions->imageBase = true; 489 490 // EGL_ANGLE_metal_create_context_ownership_identity 491 outExtensions->metalCreateContextOwnershipIdentityANGLE = true; 492 493 // EGL_ANGLE_metal_sync_shared_event 494 outExtensions->mtlSyncSharedEventANGLE = true; 495} 496 497void DisplayMtl::generateCaps(egl::Caps *outCaps) const 498{ 499 outCaps->textureNPOT = true; 500} 501 502void DisplayMtl::initializeFrontendFeatures(angle::FrontendFeatures *features) const 503{ 504 // The Metal backend's handling of compile and link is thread-safe 505 ANGLE_FEATURE_CONDITION(features, compileJobIsThreadSafe, true); 506 ANGLE_FEATURE_CONDITION(features, linkJobIsThreadSafe, true); 507} 508 509void DisplayMtl::populateFeatureList(angle::FeatureList *features) 510{ 511 mFeatures.populateFeatureList(features); 512} 513 514EGLenum DisplayMtl::EGLDrawingBufferTextureTarget() 515{ 516 // TODO(anglebug.com/42264909): Apple's implementation conditionalized this on 517 // MacCatalyst and whether it was running on ARM64 or X64, preferring 518 // EGL_TEXTURE_RECTANGLE_ANGLE. Metal can bind IOSurfaces to regular 2D 519 // textures, and rectangular textures don't work in the SPIR-V Metal 520 // backend, so for the time being use EGL_TEXTURE_2D on all platforms. 521 return EGL_TEXTURE_2D; 522} 523 524egl::ConfigSet DisplayMtl::generateConfigs() 525{ 526 // NOTE(hqle): generate more config permutations 527 egl::ConfigSet configs; 528 529 const gl::Version &maxVersion = getMaxSupportedESVersion(); 530 ASSERT(maxVersion >= gl::Version(2, 0)); 531 bool supportsES3 = maxVersion >= gl::Version(3, 0); 532 533 egl::Config config; 534 535 // Native stuff 536 config.nativeVisualID = 0; 537 config.nativeVisualType = 0; 538 config.nativeRenderable = EGL_TRUE; 539 540 config.colorBufferType = EGL_RGB_BUFFER; 541 config.luminanceSize = 0; 542 config.alphaMaskSize = 0; 543 544 config.transparentType = EGL_NONE; 545 546 // Pbuffer 547 config.bindToTextureTarget = EGLDrawingBufferTextureTarget(); 548 config.maxPBufferWidth = 4096; 549 config.maxPBufferHeight = 4096; 550 config.maxPBufferPixels = 4096 * 4096; 551 552 // Caveat 553 config.configCaveat = EGL_NONE; 554 555 // Misc 556 config.sampleBuffers = 0; 557 config.samples = 0; 558 config.level = 0; 559 config.bindToTextureRGB = EGL_FALSE; 560 config.bindToTextureRGBA = EGL_TRUE; 561 562 config.surfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT; 563 564#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 565 config.minSwapInterval = 0; 566 config.maxSwapInterval = 1; 567#else 568 config.minSwapInterval = 1; 569 config.maxSwapInterval = 1; 570#endif 571 572 config.renderTargetFormat = GL_RGBA8; 573 574 config.conformant = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0); 575 config.renderableType = config.conformant; 576 577 config.matchNativePixmap = EGL_NONE; 578 579 config.colorComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; 580 581 constexpr int samplesSupported[] = {0, 4}; 582 583 for (int samples : samplesSupported) 584 { 585 config.samples = samples; 586 config.sampleBuffers = (samples == 0) ? 0 : 1; 587 588 // Buffer sizes 589 config.redSize = 8; 590 config.greenSize = 8; 591 config.blueSize = 8; 592 config.alphaSize = 8; 593 config.bufferSize = config.redSize + config.greenSize + config.blueSize + config.alphaSize; 594 595 // With DS 596 config.depthSize = 24; 597 config.stencilSize = 8; 598 config.depthStencilFormat = GL_DEPTH24_STENCIL8; 599 600 configs.add(config); 601 602 // With D 603 config.depthSize = 24; 604 config.stencilSize = 0; 605 config.depthStencilFormat = GL_DEPTH_COMPONENT24; 606 configs.add(config); 607 608 // With S 609 config.depthSize = 0; 610 config.stencilSize = 8; 611 config.depthStencilFormat = GL_STENCIL_INDEX8; 612 configs.add(config); 613 614 // No DS 615 config.depthSize = 0; 616 config.stencilSize = 0; 617 config.depthStencilFormat = GL_NONE; 618 configs.add(config); 619 620 // Tests like dEQP-GLES2.functional.depth_range.* assume EGL_DEPTH_SIZE is properly set even 621 // if renderConfig attributes are set to glu::RenderConfig::DONT_CARE 622 config.depthSize = GetDepthSize(config.depthStencilFormat); 623 config.stencilSize = GetStencilSize(config.depthStencilFormat); 624 configs.add(config); 625 } 626 627 return configs; 628} 629 630bool DisplayMtl::isValidNativeWindow(EGLNativeWindowType window) const 631{ 632 ANGLE_MTL_OBJC_SCOPE 633 { 634 NSObject *layer = (__bridge NSObject *)(window); 635 return [layer isKindOfClass:[CALayer class]]; 636 } 637} 638 639egl::Error DisplayMtl::validateClientBuffer(const egl::Config *configuration, 640 EGLenum buftype, 641 EGLClientBuffer clientBuffer, 642 const egl::AttributeMap &attribs) const 643{ 644 switch (buftype) 645 { 646 case EGL_IOSURFACE_ANGLE: 647 if (!IOSurfaceSurfaceMtl::ValidateAttributes(clientBuffer, attribs)) 648 { 649 return egl::EglBadAttribute(); 650 } 651 break; 652 default: 653 UNREACHABLE(); 654 return egl::EglBadAttribute(); 655 } 656 return egl::NoError(); 657} 658 659egl::Error DisplayMtl::validateImageClientBuffer(const gl::Context *context, 660 EGLenum target, 661 EGLClientBuffer clientBuffer, 662 const egl::AttributeMap &attribs) const 663{ 664 switch (target) 665 { 666 case EGL_METAL_TEXTURE_ANGLE: 667 return TextureImageSiblingMtl::ValidateClientBuffer(this, clientBuffer, attribs); 668 default: 669 UNREACHABLE(); 670 return egl::EglBadAttribute(); 671 } 672} 673 674gl::Caps DisplayMtl::getNativeCaps() const 675{ 676 ensureCapsInitialized(); 677 return mNativeCaps; 678} 679const gl::TextureCapsMap &DisplayMtl::getNativeTextureCaps() const 680{ 681 ensureCapsInitialized(); 682 return mNativeTextureCaps; 683} 684const gl::Extensions &DisplayMtl::getNativeExtensions() const 685{ 686 ensureCapsInitialized(); 687 return mNativeExtensions; 688} 689const gl::Limitations &DisplayMtl::getNativeLimitations() const 690{ 691 ensureCapsInitialized(); 692 return mNativeLimitations; 693} 694const ShPixelLocalStorageOptions &DisplayMtl::getNativePixelLocalStorageOptions() const 695{ 696 ensureCapsInitialized(); 697 return mNativePLSOptions; 698} 699 700void DisplayMtl::ensureCapsInitialized() const 701{ 702 if (mCapsInitialized) 703 { 704 return; 705 } 706 707 mCapsInitialized = true; 708 709 // Reset 710 mNativeCaps = gl::Caps(); 711 712 // Fill extension and texture caps 713 initializeExtensions(); 714 initializeTextureCaps(); 715 716 // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf 717 mNativeCaps.maxElementIndex = std::numeric_limits<GLuint>::max() - 1; 718 mNativeCaps.max3DTextureSize = 2048; 719#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 720 mNativeCaps.max2DTextureSize = 16384; 721 // On macOS exclude [[position]] from maxVaryingVectors. 722 mNativeCaps.maxVaryingVectors = 31 - 1; 723 mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxFragmentInputComponents = 124 - 4; 724#elif TARGET_OS_SIMULATOR 725 mNativeCaps.max2DTextureSize = 8192; 726 mNativeCaps.maxVaryingVectors = 31 - 1; 727 mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxFragmentInputComponents = 124 - 4; 728#else 729 if (supportsAppleGPUFamily(3)) 730 { 731 mNativeCaps.max2DTextureSize = 16384; 732 mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxFragmentInputComponents = 124; 733 mNativeCaps.maxVaryingVectors = mNativeCaps.maxVertexOutputComponents / 4; 734 } 735 else 736 { 737 mNativeCaps.max2DTextureSize = 8192; 738 mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxFragmentInputComponents = 60; 739 mNativeCaps.maxVaryingVectors = mNativeCaps.maxVertexOutputComponents / 4; 740 } 741#endif 742 743 mNativeCaps.maxArrayTextureLayers = 2048; 744 mNativeCaps.maxLODBias = std::log2(mNativeCaps.max2DTextureSize) + 1; 745 mNativeCaps.maxCubeMapTextureSize = mNativeCaps.max2DTextureSize; 746 mNativeCaps.maxRenderbufferSize = mNativeCaps.max2DTextureSize; 747 mNativeCaps.minAliasedPointSize = 1; 748 // NOTE(hqle): Metal has some problems drawing big point size even though 749 // Metal-Feature-Set-Tables.pdf says that max supported point size is 511. We limit it to 64 750 // for now. http://anglebug.com/42263403 751 752 // NOTE(kpiddington): This seems to be fixed in macOS Monterey 753 if (@available(macOS 12.0, *)) 754 { 755 mNativeCaps.maxAliasedPointSize = 511; 756 } 757 else 758 { 759 mNativeCaps.maxAliasedPointSize = 64; 760 } 761 mNativeCaps.minAliasedLineWidth = 1.0f; 762 mNativeCaps.maxAliasedLineWidth = 1.0f; 763 764 if (supportsEitherGPUFamily(2, 1) && !mFeatures.limitMaxDrawBuffersForTesting.enabled) 765 { 766 mNativeCaps.maxDrawBuffers = mtl::kMaxRenderTargets; 767 mNativeCaps.maxColorAttachments = mtl::kMaxRenderTargets; 768 } 769 else 770 { 771 mNativeCaps.maxDrawBuffers = mtl::kMaxRenderTargetsOlderGPUFamilies; 772 mNativeCaps.maxColorAttachments = mtl::kMaxRenderTargetsOlderGPUFamilies; 773 } 774 ASSERT(static_cast<uint32_t>(mNativeCaps.maxDrawBuffers) <= mtl::kMaxRenderTargets); 775 ASSERT(static_cast<uint32_t>(mNativeCaps.maxColorAttachments) <= mtl::kMaxRenderTargets); 776 777 mNativeCaps.maxFramebufferWidth = mNativeCaps.max2DTextureSize; 778 mNativeCaps.maxFramebufferHeight = mNativeCaps.max2DTextureSize; 779 mNativeCaps.maxViewportWidth = mNativeCaps.max2DTextureSize; 780 mNativeCaps.maxViewportHeight = mNativeCaps.max2DTextureSize; 781 782 bool isCatalyst = TARGET_OS_MACCATALYST; 783 784 mMaxColorTargetBits = mtl::kMaxColorTargetBitsApple1To3; 785 if (supportsMacGPUFamily(1) || isCatalyst) 786 { 787 mMaxColorTargetBits = mtl::kMaxColorTargetBitsMacAndCatalyst; 788 } 789 else if (supportsAppleGPUFamily(4)) 790 { 791 mMaxColorTargetBits = mtl::kMaxColorTargetBitsApple4Plus; 792 } 793 794 if (mFeatures.limitMaxColorTargetBitsForTesting.enabled) 795 { 796 // Set so we have enough for RGBA8 on every attachment 797 // but not enough for RGBA32UI. 798 mMaxColorTargetBits = mNativeCaps.maxColorAttachments * 32; 799 } 800 801 // MSAA 802 mNativeCaps.maxSamples = mFormatTable.getMaxSamples(); 803 mNativeCaps.maxSampleMaskWords = 1; 804 mNativeCaps.maxColorTextureSamples = mNativeCaps.maxSamples; 805 mNativeCaps.maxDepthTextureSamples = mNativeCaps.maxSamples; 806 mNativeCaps.maxIntegerSamples = mNativeCaps.maxSamples; 807 808 mNativeCaps.maxVertexAttributes = mtl::kMaxVertexAttribs; 809 mNativeCaps.maxVertexAttribBindings = mtl::kMaxVertexAttribs; 810 mNativeCaps.maxVertexAttribRelativeOffset = std::numeric_limits<GLint>::max(); 811 mNativeCaps.maxVertexAttribStride = std::numeric_limits<GLint>::max(); 812 813 // glGet() use signed integer as parameter so we have to use GLint's max here, not GLuint. 814 mNativeCaps.maxElementsIndices = std::numeric_limits<GLint>::max(); 815 mNativeCaps.maxElementsVertices = std::numeric_limits<GLint>::max(); 816 817 // Looks like all floats are IEEE according to the docs here: 818 mNativeCaps.vertexHighpFloat.setIEEEFloat(); 819 mNativeCaps.vertexMediumpFloat.setIEEEFloat(); 820 mNativeCaps.vertexLowpFloat.setIEEEFloat(); 821 mNativeCaps.fragmentHighpFloat.setIEEEFloat(); 822 mNativeCaps.fragmentMediumpFloat.setIEEEFloat(); 823 mNativeCaps.fragmentLowpFloat.setIEEEFloat(); 824 825 mNativeCaps.vertexHighpInt.setTwosComplementInt(32); 826 mNativeCaps.vertexMediumpInt.setTwosComplementInt(32); 827 mNativeCaps.vertexLowpInt.setTwosComplementInt(32); 828 mNativeCaps.fragmentHighpInt.setTwosComplementInt(32); 829 mNativeCaps.fragmentMediumpInt.setTwosComplementInt(32); 830 mNativeCaps.fragmentLowpInt.setTwosComplementInt(32); 831 832 GLuint maxDefaultUniformVectors = mtl::kDefaultUniformsMaxSize / (sizeof(GLfloat) * 4); 833 834 const GLuint maxDefaultUniformComponents = maxDefaultUniformVectors * 4; 835 836 // Uniforms are implemented using a uniform buffer, so the max number of uniforms we can 837 // support is the max buffer range divided by the size of a single uniform (4X float). 838 mNativeCaps.maxVertexUniformVectors = maxDefaultUniformVectors; 839 mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Vertex] = maxDefaultUniformComponents; 840 mNativeCaps.maxFragmentUniformVectors = maxDefaultUniformVectors; 841 mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Fragment] = maxDefaultUniformComponents; 842 843 mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Vertex] = mtl::kMaxShaderUBOs; 844 mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Fragment] = mtl::kMaxShaderUBOs; 845 mNativeCaps.maxCombinedUniformBlocks = mtl::kMaxGLUBOBindings; 846 847 // Note that we currently implement textures as combined image+samplers, so the limit is 848 // the minimum of supported samplers and sampled images. 849 mNativeCaps.maxCombinedTextureImageUnits = mtl::kMaxGLSamplerBindings; 850 mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment] = mtl::kMaxShaderSamplers; 851 mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex] = mtl::kMaxShaderSamplers; 852 853 // No info from Metal given, use default GLES3 spec values: 854 mNativeCaps.minProgramTexelOffset = -8; 855 mNativeCaps.maxProgramTexelOffset = 7; 856 857 // NOTE(hqle): support storage buffer. 858 const uint32_t maxPerStageStorageBuffers = 0; 859 mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] = maxPerStageStorageBuffers; 860 mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] = maxPerStageStorageBuffers; 861 mNativeCaps.maxCombinedShaderStorageBlocks = maxPerStageStorageBuffers; 862 863 // Fill in additional limits for UBOs and SSBOs. 864 mNativeCaps.maxUniformBufferBindings = mNativeCaps.maxCombinedUniformBlocks; 865 mNativeCaps.maxUniformBlockSize = mtl::kMaxUBOSize; // Default according to GLES 3.0 spec. 866 if (supportsAppleGPUFamily(1)) 867 { 868 mNativeCaps.uniformBufferOffsetAlignment = 869 16; // on Apple based GPU's We can ignore data types when setting constant buffer 870 // alignment at 16. 871 } 872 else 873 { 874 mNativeCaps.uniformBufferOffsetAlignment = 875 256; // constant buffers on all other GPUs must be aligned to 256. 876 } 877 878 mNativeCaps.maxShaderStorageBufferBindings = 0; 879 mNativeCaps.maxShaderStorageBlockSize = 0; 880 mNativeCaps.shaderStorageBufferOffsetAlignment = 0; 881 882 // UBO plus default uniform limits 883 const uint32_t maxCombinedUniformComponents = 884 maxDefaultUniformComponents + mtl::kMaxUBOSize * mtl::kMaxShaderUBOs / 4; 885 for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes) 886 { 887 mNativeCaps.maxCombinedShaderUniformComponents[shaderType] = maxCombinedUniformComponents; 888 } 889 890 mNativeCaps.maxCombinedShaderOutputResources = 0; 891 892 mNativeCaps.maxTransformFeedbackInterleavedComponents = 893 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; 894 mNativeCaps.maxTransformFeedbackSeparateAttributes = 895 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS; 896 mNativeCaps.maxTransformFeedbackSeparateComponents = 897 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS; 898 899 // GL_OES_get_program_binary 900 mNativeCaps.programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); 901 902 // GL_APPLE_clip_distance / GL_ANGLE_clip_cull_distance 903 mNativeCaps.maxClipDistances = 8; 904 905 // Metal doesn't support GL_TEXTURE_COMPARE_MODE=GL_NONE for shadow samplers 906 mNativeLimitations.noShadowSamplerCompareModeNone = true; 907 908 // Apple platforms require PVRTC1 textures to be squares. 909 mNativeLimitations.squarePvrtc1 = true; 910} 911 912void DisplayMtl::initializeExtensions() const 913{ 914 // Reset 915 mNativeExtensions = gl::Extensions(); 916 917 // Enable this for simple buffer readback testing, but some functionality is missing. 918 // NOTE(hqle): Support full mapBufferRangeEXT extension. 919 mNativeExtensions.mapbufferOES = true; 920 mNativeExtensions.mapBufferRangeEXT = true; 921 mNativeExtensions.textureStorageEXT = true; 922 mNativeExtensions.clipControlEXT = true; 923 mNativeExtensions.drawBuffersEXT = true; 924 mNativeExtensions.drawBuffersIndexedEXT = true; 925 mNativeExtensions.drawBuffersIndexedOES = true; 926 mNativeExtensions.fboRenderMipmapOES = true; 927 mNativeExtensions.fragDepthEXT = true; 928 mNativeExtensions.conservativeDepthEXT = true; 929 mNativeExtensions.framebufferBlitANGLE = true; 930 mNativeExtensions.framebufferBlitNV = true; 931 mNativeExtensions.framebufferMultisampleANGLE = true; 932 mNativeExtensions.polygonModeANGLE = true; 933 mNativeExtensions.polygonOffsetClampEXT = true; 934 mNativeExtensions.stencilTexturingANGLE = true; 935 mNativeExtensions.copyTextureCHROMIUM = true; 936 mNativeExtensions.copyCompressedTextureCHROMIUM = false; 937 mNativeExtensions.textureMirrorClampToEdgeEXT = true; 938 mNativeExtensions.depthClampEXT = true; 939 940 // EXT_debug_marker is not implemented yet, but the entry points must be exposed for the 941 // Metal backend to be used in Chrome (http://anglebug.com/42263519) 942 mNativeExtensions.debugMarkerEXT = true; 943 944 mNativeExtensions.robustnessEXT = true; 945 mNativeExtensions.robustnessKHR = true; 946 mNativeExtensions.textureBorderClampOES = false; // not implemented yet 947 mNativeExtensions.multiDrawIndirectEXT = true; 948 mNativeExtensions.translatedShaderSourceANGLE = true; 949 mNativeExtensions.discardFramebufferEXT = true; 950 // TODO(anglebug.com/42264909): Apple's implementation exposed 951 // mNativeExtensions.textureRectangle = true here and 952 // EGL_TEXTURE_RECTANGLE_ANGLE as the eglBindTexImage texture target on 953 // macOS. This no longer seems necessary as IOSurfaces can be bound to 954 // regular 2D textures with Metal, and causes other problems such as 955 // breaking the SPIR-V Metal compiler. 956 957 mNativeExtensions.multisampledRenderToTextureEXT = 958 (supportsAppleGPUFamily(1) || 959 mFeatures.enableMultisampledRenderToTextureOnNonTilers.enabled) && 960 mFeatures.hasShaderStencilOutput.enabled && mFeatures.hasDepthAutoResolve.enabled && 961 mFeatures.hasStencilAutoResolve.enabled; 962 963 // Enable EXT_blend_minmax 964 mNativeExtensions.blendMinmaxEXT = true; 965 966 mNativeExtensions.EGLImageOES = true; 967 mNativeExtensions.EGLImageExternalOES = false; 968 // NOTE(hqle): Support GL_OES_EGL_image_external_essl3. 969 mNativeExtensions.EGLImageExternalEssl3OES = false; 970 971 mNativeExtensions.memoryObjectEXT = false; 972 mNativeExtensions.memoryObjectFdEXT = false; 973 974 mNativeExtensions.semaphoreEXT = false; 975 mNativeExtensions.semaphoreFdEXT = false; 976 977 mNativeExtensions.instancedArraysANGLE = true; 978 mNativeExtensions.instancedArraysEXT = mNativeExtensions.instancedArraysANGLE; 979 980 mNativeExtensions.robustBufferAccessBehaviorKHR = false; 981 982 mNativeExtensions.EGLSyncOES = false; 983 984 mNativeExtensions.occlusionQueryBooleanEXT = true; 985 986 mNativeExtensions.disjointTimerQueryEXT = true; 987 mNativeCaps.queryCounterBitsTimeElapsed = 64; 988 mNativeCaps.queryCounterBitsTimestamp = 0; 989 990 mNativeExtensions.textureFilterAnisotropicEXT = true; 991 mNativeCaps.maxTextureAnisotropy = 16; 992 993 mNativeExtensions.textureNpotOES = true; 994 995 mNativeExtensions.texture3DOES = true; 996 997 mNativeExtensions.textureShadowLodEXT = true; 998 999 if ([mMetalDevice areProgrammableSamplePositionsSupported]) 1000 { 1001 mNativeExtensions.textureMultisampleANGLE = true; 1002 } 1003 1004 mNativeExtensions.sampleVariablesOES = true; 1005 1006 if ([mMetalDevice supportsPullModelInterpolation]) 1007 { 1008 mNativeExtensions.shaderMultisampleInterpolationOES = true; 1009 mNativeCaps.subPixelInterpolationOffsetBits = 4; 1010 if (supportsAppleGPUFamily(1)) 1011 { 1012 mNativeCaps.minInterpolationOffset = -0.5f; 1013 mNativeCaps.maxInterpolationOffset = +0.5f; 1014 } 1015 else 1016 { 1017 // On non-Apple GPUs, the actual range is usually 1018 // [-0.5, +0.4375] but due to framebuffer Y-flip 1019 // the effective range for the Y direction will be 1020 // [-0.4375, +0.5] when the default FBO is bound. 1021 mNativeCaps.minInterpolationOffset = -0.4375f; // -0.5 + (2 ^ -4) 1022 mNativeCaps.maxInterpolationOffset = +0.4375f; // +0.5 - (2 ^ -4) 1023 } 1024 } 1025 1026 mNativeExtensions.shaderNoperspectiveInterpolationNV = true; 1027 1028 mNativeExtensions.shaderTextureLodEXT = true; 1029 1030 mNativeExtensions.standardDerivativesOES = true; 1031 1032 mNativeExtensions.elementIndexUintOES = true; 1033 1034 // GL_OES_get_program_binary 1035 mNativeExtensions.getProgramBinaryOES = true; 1036 1037 // GL_APPLE_clip_distance 1038 mNativeExtensions.clipDistanceAPPLE = true; 1039 1040 // GL_ANGLE_clip_cull_distance 1041 mNativeExtensions.clipCullDistanceANGLE = true; 1042 1043 // GL_NV_pixel_buffer_object 1044 mNativeExtensions.pixelBufferObjectNV = true; 1045 1046 mNativeExtensions.packReverseRowOrderANGLE = true; 1047 1048 if (mFeatures.hasEvents.enabled) 1049 { 1050 // MTLSharedEvent is only available since Metal 2.1 1051 1052 // GL_NV_fence 1053 mNativeExtensions.fenceNV = true; 1054 1055 // GL_OES_EGL_sync 1056 mNativeExtensions.EGLSyncOES = true; 1057 1058 // GL_ARB_sync 1059 mNativeExtensions.syncARB = true; 1060 } 1061 1062 // GL_KHR_parallel_shader_compile 1063 mNativeExtensions.parallelShaderCompileKHR = true; 1064 1065 mNativeExtensions.baseInstanceEXT = mFeatures.hasBaseVertexInstancedDraw.enabled; 1066 mNativeExtensions.baseVertexBaseInstanceANGLE = mFeatures.hasBaseVertexInstancedDraw.enabled; 1067 mNativeExtensions.baseVertexBaseInstanceShaderBuiltinANGLE = 1068 mFeatures.hasBaseVertexInstancedDraw.enabled; 1069 1070 // Metal uses the opposite provoking vertex as GLES so emulation is required to use the GLES 1071 // behaviour. Allow users to change the provoking vertex for improved performance. 1072 mNativeExtensions.provokingVertexANGLE = true; 1073 1074 // GL_EXT_blend_func_extended 1075 mNativeExtensions.blendFuncExtendedEXT = true; 1076 mNativeCaps.maxDualSourceDrawBuffers = 1; 1077 1078 // GL_ANGLE_shader_pixel_local_storage. 1079 if (!mFeatures.disableProgrammableBlending.enabled && supportsAppleGPUFamily(1)) 1080 { 1081 // Programmable blending is supported on all Apple GPU families, and is always coherent. 1082 mNativePLSOptions.type = ShPixelLocalStorageType::FramebufferFetch; 1083 1084 // Raster order groups are NOT required to make framebuffer fetch coherent, however, they 1085 // may improve performance by allowing finer grained synchronization (e.g., by assigning 1086 // attachments to different raster order groups when they don't depend on each other). 1087 bool rasterOrderGroupsSupported = 1088 !mFeatures.disableRasterOrderGroups.enabled && supportsAppleGPUFamily(4); 1089 mNativePLSOptions.fragmentSyncType = 1090 rasterOrderGroupsSupported ? ShFragmentSynchronizationType::RasterOrderGroups_Metal 1091 : ShFragmentSynchronizationType::Automatic; 1092 1093 mNativeExtensions.shaderPixelLocalStorageANGLE = true; 1094 mNativeExtensions.shaderPixelLocalStorageCoherentANGLE = true; 1095 } 1096 else 1097 { 1098 MTLReadWriteTextureTier readWriteTextureTier = [mMetalDevice readWriteTextureSupport]; 1099 if (readWriteTextureTier != MTLReadWriteTextureTierNone) 1100 { 1101 mNativePLSOptions.type = ShPixelLocalStorageType::ImageLoadStore; 1102 1103 // Raster order groups are required to make PLS coherent when using read_write textures. 1104 bool rasterOrderGroupsSupported = !mFeatures.disableRasterOrderGroups.enabled && 1105 [mMetalDevice areRasterOrderGroupsSupported]; 1106 mNativePLSOptions.fragmentSyncType = 1107 rasterOrderGroupsSupported ? ShFragmentSynchronizationType::RasterOrderGroups_Metal 1108 : ShFragmentSynchronizationType::NotSupported; 1109 1110 mNativePLSOptions.supportsNativeRGBA8ImageFormats = 1111 !mFeatures.disableRWTextureTier2Support.enabled && 1112 readWriteTextureTier == MTLReadWriteTextureTier2; 1113 1114 if (rasterOrderGroupsSupported && isAMD()) 1115 { 1116 // anglebug.com/42266263 -- [[raster_order_group()]] does not work for read_write 1117 // textures on AMD when the render pass doesn't have a color attachment on slot 0. 1118 // To work around this we attach one of the PLS textures to GL_COLOR_ATTACHMENT0, if 1119 // there isn't one already. 1120 mNativePLSOptions.renderPassNeedsAMDRasterOrderGroupsWorkaround = true; 1121 } 1122 1123 mNativeExtensions.shaderPixelLocalStorageANGLE = true; 1124 mNativeExtensions.shaderPixelLocalStorageCoherentANGLE = rasterOrderGroupsSupported; 1125 1126 // Set up PLS caps here because the higher level context won't have enough info to set 1127 // them up itself. Shader images and other ES3.1 caps aren't fully exposed yet. 1128 static_assert(mtl::kMaxShaderImages >= 1129 gl::IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES); 1130 mNativeCaps.maxPixelLocalStoragePlanes = 1131 gl::IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES; 1132 mNativeCaps.maxColorAttachmentsWithActivePixelLocalStorage = 1133 gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; 1134 mNativeCaps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes = 1135 gl::IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES + 1136 gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; 1137 mNativeCaps.maxShaderImageUniforms[gl::ShaderType::Fragment] = 1138 gl::IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES; 1139 mNativeCaps.maxImageUnits = gl::IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES; 1140 } 1141 } 1142 // "The GPUs in Apple3 through Apple8 families only support memory barriers for compute command 1143 // encoders, and for vertex-to-vertex and vertex-to-fragment stages of render command encoders." 1144 mHasFragmentMemoryBarriers = !supportsAppleGPUFamily(3); 1145} 1146 1147void DisplayMtl::initializeTextureCaps() const 1148{ 1149 mNativeTextureCaps.clear(); 1150 1151 mFormatTable.generateTextureCaps(this, &mNativeTextureCaps); 1152 1153 // Re-verify texture extensions. 1154 mNativeExtensions.setTextureExtensionSupport(mNativeTextureCaps); 1155 1156 // When ETC2/EAC formats are natively supported, enable ANGLE-specific extension string to 1157 // expose them to WebGL. In other case, mark potentially-available ETC1 extension as 1158 // emulated. 1159 if (supportsAppleGPUFamily(1) && gl::DetermineCompressedTextureETCSupport(mNativeTextureCaps)) 1160 { 1161 mNativeExtensions.compressedTextureEtcANGLE = true; 1162 } 1163 else 1164 { 1165 mNativeLimitations.emulatedEtc1 = true; 1166 } 1167 1168 // Enable EXT_compressed_ETC1_RGB8_sub_texture if ETC1 is supported. 1169 mNativeExtensions.compressedETC1RGB8SubTextureEXT = 1170 mNativeExtensions.compressedETC1RGB8TextureOES; 1171 1172 // Enable ASTC sliced 3D, requires MTLGPUFamilyApple3 1173 if (supportsAppleGPUFamily(3) && mNativeExtensions.textureCompressionAstcLdrKHR) 1174 { 1175 mNativeExtensions.textureCompressionAstcSliced3dKHR = true; 1176 } 1177 1178 // Enable ASTC HDR, requires MTLGPUFamilyApple6 1179 if (supportsAppleGPUFamily(6) && mNativeExtensions.textureCompressionAstcLdrKHR) 1180 { 1181 mNativeExtensions.textureCompressionAstcHdrKHR = true; 1182 } 1183 1184 // Disable all depth buffer and stencil buffer readback extensions until we need them 1185 mNativeExtensions.readDepthNV = false; 1186 mNativeExtensions.readStencilNV = false; 1187 mNativeExtensions.depthBufferFloat2NV = false; 1188} 1189 1190void DisplayMtl::initializeLimitations() 1191{ 1192 mNativeLimitations.noVertexAttributeAliasing = true; 1193} 1194 1195void DisplayMtl::initializeFeatures() 1196{ 1197 bool isOSX = TARGET_OS_OSX; 1198 bool isCatalyst = TARGET_OS_MACCATALYST; 1199 bool isSimulator = TARGET_OS_SIMULATOR; 1200 bool isARM = ANGLE_APPLE_IS_ARM; 1201 1202 ApplyFeatureOverrides(&mFeatures, getState().featureOverrides); 1203 if (mState.featureOverrides.allDisabled) 1204 { 1205 return; 1206 } 1207 1208 ANGLE_FEATURE_CONDITION((&mFeatures), allowGenMultipleMipsPerPass, true); 1209 ANGLE_FEATURE_CONDITION((&mFeatures), forceBufferGPUStorage, false); 1210 ANGLE_FEATURE_CONDITION((&mFeatures), hasExplicitMemBarrier, (isOSX || isCatalyst) && !isARM); 1211 ANGLE_FEATURE_CONDITION((&mFeatures), hasDepthAutoResolve, supportsEitherGPUFamily(3, 2)); 1212 ANGLE_FEATURE_CONDITION((&mFeatures), hasStencilAutoResolve, supportsEitherGPUFamily(5, 2)); 1213 ANGLE_FEATURE_CONDITION((&mFeatures), allowMultisampleStoreAndResolve, 1214 supportsEitherGPUFamily(3, 1)); 1215 1216 // Apple2 does not support comparison functions in MTLSamplerState 1217 ANGLE_FEATURE_CONDITION((&mFeatures), allowRuntimeSamplerCompareMode, 1218 supportsEitherGPUFamily(3, 1)); 1219 1220 // AMD does not support sample_compare with gradients 1221 ANGLE_FEATURE_CONDITION((&mFeatures), allowSamplerCompareGradient, !isAMD()); 1222 1223 // http://anglebug.com/40644746 1224 // Stencil blit shader is not compiled on Intel & NVIDIA, need investigation. 1225 ANGLE_FEATURE_CONDITION((&mFeatures), hasShaderStencilOutput, !isIntel() && !isNVIDIA()); 1226 1227 ANGLE_FEATURE_CONDITION((&mFeatures), hasTextureSwizzle, 1228 supportsEitherGPUFamily(3, 2) && !isSimulator); 1229 1230 ANGLE_FEATURE_CONDITION((&mFeatures), avoidStencilTextureSwizzle, isIntel()); 1231 1232 // http://crbug.com/1136673 1233 // Fence sync is flaky on Nvidia 1234 ANGLE_FEATURE_CONDITION((&mFeatures), hasEvents, !isNVIDIA()); 1235 1236 ANGLE_FEATURE_CONDITION((&mFeatures), hasCheapRenderPass, (isOSX || isCatalyst) && !isARM); 1237 1238 // http://anglebug.com/42263788 1239 // D24S8 is unreliable on AMD. 1240 ANGLE_FEATURE_CONDITION((&mFeatures), forceD24S8AsUnsupported, isAMD()); 1241 1242 // Base Vertex drawing is only supported since GPU family 3. 1243 ANGLE_FEATURE_CONDITION((&mFeatures), hasBaseVertexInstancedDraw, 1244 isOSX || isCatalyst || supportsAppleGPUFamily(3)); 1245 1246 ANGLE_FEATURE_CONDITION((&mFeatures), hasNonUniformDispatch, 1247 isOSX || isCatalyst || supportsAppleGPUFamily(4)); 1248 1249 ANGLE_FEATURE_CONDITION((&mFeatures), allowSeparateDepthStencilBuffers, 1250 supportsAppleGPUFamily(1) && !isSimulator); 1251 ANGLE_FEATURE_CONDITION((&mFeatures), emulateTransformFeedback, true); 1252 1253 ANGLE_FEATURE_CONDITION((&mFeatures), intelExplicitBoolCastWorkaround, 1254 isIntel() && GetMacOSVersion() < OSVersion(11, 0, 0)); 1255 ANGLE_FEATURE_CONDITION((&mFeatures), intelDisableFastMath, 1256 isIntel() && GetMacOSVersion() < OSVersion(12, 0, 0)); 1257 1258 ANGLE_FEATURE_CONDITION((&mFeatures), emulateAlphaToCoverage, 1259 isSimulator || !supportsAppleGPUFamily(1)); 1260 1261 ANGLE_FEATURE_CONDITION((&mFeatures), writeHelperSampleMask, supportsAppleGPUFamily(1)); 1262 1263 ANGLE_FEATURE_CONDITION((&mFeatures), multisampleColorFormatShaderReadWorkaround, isAMD()); 1264 ANGLE_FEATURE_CONDITION((&mFeatures), copyIOSurfaceToNonIOSurfaceForReadOptimization, 1265 isIntel() || isAMD()); 1266 ANGLE_FEATURE_CONDITION((&mFeatures), copyTextureToBufferForReadOptimization, isAMD()); 1267 1268 ANGLE_FEATURE_CONDITION((&mFeatures), forceNonCSBaseMipmapGeneration, isIntel()); 1269 1270 ANGLE_FEATURE_CONDITION((&mFeatures), preemptivelyStartProvokingVertexCommandBuffer, isAMD()); 1271 1272 ANGLE_FEATURE_CONDITION((&mFeatures), alwaysUseStagedBufferUpdates, isAMD()); 1273 ANGLE_FEATURE_CONDITION((&mFeatures), alwaysUseManagedStorageModeForBuffers, isAMD()); 1274 1275 ANGLE_FEATURE_CONDITION((&mFeatures), alwaysUseSharedStorageModeForBuffers, isIntel()); 1276 ANGLE_FEATURE_CONDITION((&mFeatures), useShadowBuffersWhenAppropriate, isIntel()); 1277 1278 // At least one of these must not be set. 1279 ASSERT(!mFeatures.alwaysUseManagedStorageModeForBuffers.enabled || 1280 !mFeatures.alwaysUseSharedStorageModeForBuffers.enabled); 1281 1282 ANGLE_FEATURE_CONDITION((&mFeatures), uploadDataToIosurfacesWithStagingBuffers, isAMD()); 1283 1284 // Render passes can be rendered without attachments on Apple4 , mac2 hardware. 1285 ANGLE_FEATURE_CONDITION(&(mFeatures), allowRenderpassWithoutAttachment, 1286 supportsEitherGPUFamily(4, 2)); 1287 1288 ANGLE_FEATURE_CONDITION((&mFeatures), enableInMemoryMtlLibraryCache, true); 1289 ANGLE_FEATURE_CONDITION((&mFeatures), enableParallelMtlLibraryCompilation, true); 1290 1291 // Uploading texture data via staging buffers improves performance on all tested systems. 1292 // http://anglebug.com/40644905: Disabled on intel due to some texture formats uploading 1293 // incorrectly with staging buffers 1294 ANGLE_FEATURE_CONDITION(&mFeatures, alwaysPreferStagedTextureUploads, true); 1295 ANGLE_FEATURE_CONDITION(&mFeatures, disableStagedInitializationOfPackedTextureFormats, 1296 isIntel() || isAMD()); 1297 1298 ANGLE_FEATURE_CONDITION((&mFeatures), generateShareableShaders, true); 1299 1300 // http://anglebug.com/42266609: NVIDIA GPUs are unsupported due to scarcity of the hardware. 1301 ANGLE_FEATURE_CONDITION((&mFeatures), disableMetalOnNvidia, true); 1302 1303 // The AMDMTLBronzeDriver seems to have bugs flushing vertex data to the GPU during some kinds 1304 // of buffer uploads which require a flush to work around. 1305 ANGLE_FEATURE_CONDITION((&mFeatures), flushAfterStreamVertexData, isAMDBronzeDriver()); 1306 1307 // TODO(anglebug.com/40096869): GPUs that don't support Mac GPU family 2 or greater are 1308 // unsupported by the Metal backend. 1309 ANGLE_FEATURE_CONDITION((&mFeatures), requireGpuFamily2, true); 1310 1311 // http://anglebug.com/42266744: Rescope global variables which are only used in one function to 1312 // be function local. Disabled on AMD FirePro devices: http://anglebug.com/40096898 1313 ANGLE_FEATURE_CONDITION((&mFeatures), rescopeGlobalVariables, !isAMDFireProDevice()); 1314 1315 // Apple-specific pre-transform for explicit cubemap derivatives 1316 ANGLE_FEATURE_CONDITION((&mFeatures), preTransformTextureCubeGradDerivatives, 1317 supportsAppleGPUFamily(1)); 1318 1319 // Apple-specific cubemap derivative transformation is not compatible with 1320 // the textureGrad shadow sampler emulation. The latter is used only on AMD. 1321 ASSERT(!mFeatures.preTransformTextureCubeGradDerivatives.enabled || 1322 mFeatures.allowSamplerCompareGradient.enabled); 1323 1324 // Metal compiler optimizations may remove infinite loops causing crashes later in shader 1325 // execution. http://crbug.com/1513738 1326 // Disabled on Mac11 due to test failures. http://crbug.com/1522730 1327 ANGLE_FEATURE_CONDITION((&mFeatures), injectAsmStatementIntoLoopBodies, 1328 !isOSX || GetMacOSVersion() >= OSVersion(12, 0, 0)); 1329} 1330 1331angle::Result DisplayMtl::initializeShaderLibrary() 1332{ 1333 mtl::AutoObjCPtr<NSError *> err = nil; 1334#if ANGLE_METAL_XCODE_BUILDS_SHADERS || ANGLE_METAL_HAS_PREBUILT_INTERNAL_SHADERS 1335 mDefaultShaders = mtl::CreateShaderLibraryFromStaticBinary(getMetalDevice(), gDefaultMetallib, 1336 std::size(gDefaultMetallib), &err); 1337#else 1338 const bool disableFastMath = false; 1339 const bool usesInvariance = true; 1340 mDefaultShaders = mtl::CreateShaderLibrary(getMetalDevice(), gDefaultMetallibSrc, {}, 1341 disableFastMath, usesInvariance, &err); 1342#endif 1343 1344 if (err) 1345 { 1346 ERR() << "Internal error: " << err.get().localizedDescription.UTF8String; 1347 return angle::Result::Stop; 1348 } 1349 1350 return angle::Result::Continue; 1351} 1352 1353id<MTLLibrary> DisplayMtl::getDefaultShadersLib() 1354{ 1355 return mDefaultShaders; 1356} 1357 1358bool DisplayMtl::supportsAppleGPUFamily(uint8_t iOSFamily) const 1359{ 1360 return mtl::SupportsAppleGPUFamily(getMetalDevice(), iOSFamily); 1361} 1362 1363bool DisplayMtl::supportsMacGPUFamily(uint8_t macFamily) const 1364{ 1365 return mtl::SupportsMacGPUFamily(getMetalDevice(), macFamily); 1366} 1367 1368bool DisplayMtl::supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) const 1369{ 1370 return supportsAppleGPUFamily(iOSFamily) || supportsMacGPUFamily(macFamily); 1371} 1372 1373bool DisplayMtl::supports32BitFloatFiltering() const 1374{ 1375#if !TARGET_OS_WATCH 1376 return [mMetalDevice supports32BitFloatFiltering]; 1377#else 1378 return false; 1379#endif 1380} 1381 1382bool DisplayMtl::supportsBCTextureCompression() const 1383{ 1384 if (@available(macCatalyst 16.4, iOS 16.4, *)) 1385 { 1386 return [mMetalDevice supportsBCTextureCompression]; 1387 } 1388#if TARGET_OS_MACCATALYST 1389 return true; // Always true on old Catalyst 1390#else 1391 return false; // Always false on old iOS 1392#endif 1393} 1394 1395bool DisplayMtl::supportsDepth24Stencil8PixelFormat() const 1396{ 1397#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 1398 return [mMetalDevice isDepth24Stencil8PixelFormatSupported]; 1399#else 1400 return false; 1401#endif 1402} 1403bool DisplayMtl::isAMD() const 1404{ 1405 return angle::IsAMD(mMetalDeviceVendorId); 1406} 1407bool DisplayMtl::isAMDBronzeDriver() const 1408{ 1409 if (!isAMD()) 1410 { 1411 return false; 1412 } 1413 1414 if (mComputedAMDBronze) 1415 { 1416 return mIsAMDBronze; 1417 } 1418 1419 // All devices known to be covered by AMDMTlBronzeDriver. 1420 // 1421 // Note that we can not compare substrings because some devices 1422 // (AMD Radeon Pro 560) are substrings of ones supported by a 1423 // later driver (AMD Radeon Pro 5600M). 1424 NSString *kMTLBronzeDeviceNames[22] = { 1425 @"FirePro D300", @"FirePro D500", @"FirePro D700", @"Radeon R9 M290", 1426 @"Radeon R9 M290X", @"Radeon R9 M370X", @"Radeon R9 M380", @"Radeon R9 M390", 1427 @"Radeon R9 M395", @"Radeon Pro 450", @"Radeon Pro 455", @"Radeon Pro 460", 1428 @"Radeon Pro 555", @"Radeon Pro 555X", @"Radeon Pro 560", @"Radeon Pro 560X", 1429 @"Radeon Pro 570", @"Radeon Pro 570X", @"Radeon Pro 575", @"Radeon Pro 575X", 1430 @"Radeon Pro 580", @"Radeon Pro 580X"}; 1431 1432 for (size_t i = 0; i < ArraySize(kMTLBronzeDeviceNames); ++i) 1433 { 1434 if ([[mMetalDevice name] hasSuffix:kMTLBronzeDeviceNames[i]]) 1435 { 1436 mIsAMDBronze = true; 1437 break; 1438 } 1439 } 1440 1441 mComputedAMDBronze = true; 1442 return mIsAMDBronze; 1443} 1444 1445bool DisplayMtl::isAMDFireProDevice() const 1446{ 1447 if (!isAMD()) 1448 { 1449 return false; 1450 } 1451 1452 return [[mMetalDevice name] containsString:@"FirePro"]; 1453} 1454 1455bool DisplayMtl::isIntel() const 1456{ 1457 return angle::IsIntel(mMetalDeviceVendorId); 1458} 1459 1460bool DisplayMtl::isNVIDIA() const 1461{ 1462 return angle::IsNVIDIA(mMetalDeviceVendorId); 1463} 1464 1465bool DisplayMtl::isSimulator() const 1466{ 1467 return TARGET_OS_SIMULATOR; 1468} 1469 1470mtl::AutoObjCObj<MTLSharedEventListener> DisplayMtl::getOrCreateSharedEventListener() 1471{ 1472 if (!mSharedEventListener) 1473 { 1474 ANGLE_MTL_OBJC_SCOPE 1475 { 1476 mSharedEventListener = [[[MTLSharedEventListener alloc] init] ANGLE_MTL_AUTORELEASE]; 1477 ASSERT(mSharedEventListener); // Failure here most probably means a sandbox issue. 1478 } 1479 } 1480 return mSharedEventListener; 1481} 1482 1483} // namespace rx 1484