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