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