Choose direct-to-Metal translator through a feature.

Define directMetalGeneration in FeaturesMtl.h. If
ANGLE_ENABLE_METAL_SPIRV is defined to 1 (still the default),
directMetalGeneration defaults to false. It can be overridden via the
standard ANGLE mechanism:
  ANGLE_FEATURE_OVERRIDES_ENABLED=directMetalGeneration

It can also be overridden by instantiating angle_end2end_tests with
the directives:
  WithDirectMetalGeneration(ES2_METAL())
  WithDirectMetalGeneration(ES3_METAL())

These directives aren't working properly yet though. The
direct-to-Metal compiler is instantiated, but the _DirectMetalGen
versions of the tests fail. They pass when switching the Metal
backend's default behavior using the above environment variable. This
will be debugged in follow-on CLs.

Thanks to syoussefi@ for the prototype of this CL:
https://chromium-review.googlesource.com/3076129

Bug: angleproject:5505
Change-Id: I188ab89abc75bf89c5ed2d90102af311feaa1960
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3079083
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Kenneth Russell <kbr@chromium.org>
diff --git a/include/platform/FeaturesMtl.h b/include/platform/FeaturesMtl.h
index 40563dc..a38c611 100644
--- a/include/platform/FeaturesMtl.h
+++ b/include/platform/FeaturesMtl.h
@@ -109,6 +109,12 @@
                                      "Direct translation to SPIR-V.", &members,
                                      "http://anglebug.com/4889"};
 
+    // Generate Metal directly instead of generating SPIR-V and then using SPIR-V Cross.  Transitory
+    // feature until the work is complete.
+    Feature directMetalGeneration = {"directMetalGeneration", FeatureCategory::MetalFeatures,
+                                     "Direct translation to Metal.", &members,
+                                     "http://anglebug.com/5505"};
+
     Feature forceNonCSBaseMipmapGeneration = {
         "force_non_cs_mipmap_gen", FeatureCategory::MetalFeatures,
         "Turn this feature on to disallow Compute Shader based mipmap generation. Compute Shader "
diff --git a/src/libANGLE/renderer/metal/CompilerMtl.h b/src/libANGLE/renderer/metal/CompilerMtl.h
index f98e615..a95d1ec 100644
--- a/src/libANGLE/renderer/metal/CompilerMtl.h
+++ b/src/libANGLE/renderer/metal/CompilerMtl.h
@@ -18,12 +18,13 @@
 class CompilerMtl : public CompilerImpl
 {
   public:
-    CompilerMtl();
+    CompilerMtl(ShShaderOutput translatorOutputType);
     ~CompilerMtl() override;
 
     ShShaderOutput getTranslatorOutputType() const override;
 
-    static bool useDirectToMSLCompiler();
+  private:
+    ShShaderOutput mTranslatorOutputType;
 };
 
 }  // namespace rx
diff --git a/src/libANGLE/renderer/metal/CompilerMtl.mm b/src/libANGLE/renderer/metal/CompilerMtl.mm
index 45eb7a6..853c5f5 100644
--- a/src/libANGLE/renderer/metal/CompilerMtl.mm
+++ b/src/libANGLE/renderer/metal/CompilerMtl.mm
@@ -12,52 +12,19 @@
 #include <stdio.h>
 
 #include "common/debug.h"
-#include "common/system_utils.h"
 
 namespace rx
 {
 
-CompilerMtl::CompilerMtl() : CompilerImpl() {}
+CompilerMtl::CompilerMtl(ShShaderOutput translatorOutputType)
+    : CompilerImpl(), mTranslatorOutputType(translatorOutputType)
+{}
 
 CompilerMtl::~CompilerMtl() {}
 
 ShShaderOutput CompilerMtl::getTranslatorOutputType() const
 {
-#ifdef ANGLE_ENABLE_ASSERTS
-    static bool outputted = false;
-#endif
-#if ANGLE_ENABLE_METAL_SPIRV
-    if (useDirectToMSLCompiler())
-    {
-#    ifdef ANGLE_ENABLE_ASSERTS
-        if (!outputted)
-        {
-            fprintf(stderr, "Using direct-to-Metal shader compiler\n");
-            outputted = true;
-        }
-#    endif
-        return SH_MSL_METAL_OUTPUT;
-    }
-    else
-    {
-#    ifdef ANGLE_ENABLE_ASSERTS
-        if (!outputted)
-        {
-            fprintf(stderr, "Using SPIR-V Metal shader compiler\n");
-            outputted = true;
-        }
-#    endif
-        return SH_SPIRV_METAL_OUTPUT;
-    }
-#else
-    return SH_MSL_METAL_OUTPUT;
-#endif
-}
-
-bool CompilerMtl::useDirectToMSLCompiler()
-{
-    static bool val = angle::GetBoolEnvironmentVar("ANGLE_USE_MSL_COMPILER");
-    return val;
+    return mTranslatorOutputType;
 }
 
 }  // namespace rx
diff --git a/src/libANGLE/renderer/metal/ContextMtl.mm b/src/libANGLE/renderer/metal/ContextMtl.mm
index a9bef89..722e01e 100644
--- a/src/libANGLE/renderer/metal/ContextMtl.mm
+++ b/src/libANGLE/renderer/metal/ContextMtl.mm
@@ -11,6 +11,7 @@
 
 #include <TargetConditionals.h>
 
+#include "GLSLANG/ShaderLang.h"
 #include "common/debug.h"
 #include "libANGLE/TransformFeedback.h"
 #include "libANGLE/renderer/metal/BufferMtl.h"
@@ -1121,7 +1122,9 @@
 // Shader creation
 CompilerImpl *ContextMtl::createCompiler()
 {
-    return new CompilerMtl();
+    ShShaderOutput outputType =
+        getDisplay()->useDirectToMetalCompiler() ? SH_MSL_METAL_OUTPUT : SH_SPIRV_METAL_OUTPUT;
+    return new CompilerMtl(outputType);
 }
 ShaderImpl *ContextMtl::createShader(const gl::ShaderState &state)
 {
diff --git a/src/libANGLE/renderer/metal/DisplayMtl.h b/src/libANGLE/renderer/metal/DisplayMtl.h
index 390dc3e..d3451f0 100644
--- a/src/libANGLE/renderer/metal/DisplayMtl.h
+++ b/src/libANGLE/renderer/metal/DisplayMtl.h
@@ -164,6 +164,9 @@
 #if ANGLE_MTL_EVENT_AVAILABLE
     mtl::AutoObjCObj<MTLSharedEventListener> getOrCreateSharedEventListener();
 #endif
+
+    bool useDirectToMetalCompiler();
+
   protected:
     void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
     void generateCaps(egl::Caps *outCaps) const override;
diff --git a/src/libANGLE/renderer/metal/DisplayMtl.mm b/src/libANGLE/renderer/metal/DisplayMtl.mm
index 50fae56..9481ab7 100644
--- a/src/libANGLE/renderer/metal/DisplayMtl.mm
+++ b/src/libANGLE/renderer/metal/DisplayMtl.mm
@@ -979,10 +979,20 @@
 
     ANGLE_FEATURE_CONDITION((&mFeatures), forceNonCSBaseMipmapGeneration, isIntel());
 
+    bool defaultDirectToMetal = true;
+#if ANGLE_ENABLE_METAL_SPIRV
+    defaultDirectToMetal = false;
+#endif
+    ANGLE_FEATURE_CONDITION((&mFeatures), directMetalGeneration, defaultDirectToMetal);
+
     angle::PlatformMethods *platform = ANGLEPlatformCurrent();
     platform->overrideFeaturesMtl(platform, &mFeatures);
 
     ApplyFeatureOverrides(&mFeatures, getState());
+#ifdef ANGLE_ENABLE_ASSERTS
+    fprintf(stderr, "Shader compiler output: %s\n",
+            mFeatures.directMetalGeneration.enabled ? "Metal" : "SPIR-V");
+#endif
 }
 
 angle::Result DisplayMtl::initializeShaderLibrary()
@@ -1253,4 +1263,9 @@
 }
 #endif
 
+bool DisplayMtl::useDirectToMetalCompiler()
+{
+    return mFeatures.directMetalGeneration.enabled;
+}
+
 }  // namespace rx
diff --git a/src/libANGLE/renderer/metal/ProgramMtl.mm b/src/libANGLE/renderer/metal/ProgramMtl.mm
index 2080247..707a3af 100644
--- a/src/libANGLE/renderer/metal/ProgramMtl.mm
+++ b/src/libANGLE/renderer/metal/ProgramMtl.mm
@@ -444,7 +444,8 @@
                                    gl::InfoLog &infoLog)
 {
 #if ANGLE_ENABLE_METAL_SPIRV
-    if (CompilerMtl::useDirectToMSLCompiler())
+    ContextMtl *contextMtl = mtl::GetImpl(glContext);
+    if (contextMtl->getDisplay()->useDirectToMetalCompiler())
     {
         return linkImplDirect(glContext, resources, infoLog);
     }
@@ -595,7 +596,7 @@
 {
     static_assert(YES == 1, "YES should have value of 1");
 #if ANGLE_ENABLE_METAL_SPIRV
-    static const bool useSpirv = !CompilerMtl::useDirectToMSLCompiler();
+    static const bool useSpirv = !context->getDisplay()->useDirectToMetalCompiler();
 #endif
 
     mtl::TranslatedShaderInfo *translatedMslInfo = &mMslShaderTranslateInfo[shaderType];
diff --git a/src/tests/test_utils/angle_test_configs.cpp b/src/tests/test_utils/angle_test_configs.cpp
index cc1b68c..33b067c 100644
--- a/src/tests/test_utils/angle_test_configs.cpp
+++ b/src/tests/test_utils/angle_test_configs.cpp
@@ -278,6 +278,11 @@
         stream << "_DirectSPIRVGen";
     }
 
+    if (pp.eglParameters.directMetalGeneration == EGL_TRUE)
+    {
+        stream << "_DirectMetalGen";
+    }
+
     return stream;
 }
 
diff --git a/src/tests/test_utils/angle_test_configs.h b/src/tests/test_utils/angle_test_configs.h
index 7fb861d..1cf3693 100644
--- a/src/tests/test_utils/angle_test_configs.h
+++ b/src/tests/test_utils/angle_test_configs.h
@@ -303,6 +303,13 @@
     directSPIRVGeneration.eglParameters.directSPIRVGeneration = EGL_TRUE;
     return directSPIRVGeneration;
 }
+
+inline PlatformParameters WithDirectMetalGeneration(const PlatformParameters &params)
+{
+    PlatformParameters directMetalGeneration                  = params;
+    directMetalGeneration.eglParameters.directMetalGeneration = EGL_TRUE;
+    return directMetalGeneration;
+}
 }  // namespace angle
 
 #endif  // ANGLE_TEST_CONFIGS_H_
diff --git a/util/EGLPlatformParameters.h b/util/EGLPlatformParameters.h
index 3387174..5442522 100644
--- a/util/EGLPlatformParameters.h
+++ b/util/EGLPlatformParameters.h
@@ -65,7 +65,8 @@
                         robustness, emulatedPrerotation, asyncCommandQueueFeatureVulkan,
                         hasExplicitMemBarrierFeatureMtl, hasCheapRenderPassFeatureMtl,
                         forceBufferGPUStorageFeatureMtl, supportsVulkanViewportFlip, emulatedVAOs,
-                        directSPIRVGeneration, captureLimits, forceRobustResourceInit);
+                        directSPIRVGeneration, captureLimits, forceRobustResourceInit,
+                        directMetalGeneration);
     }
 
     EGLint renderer                               = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
@@ -91,6 +92,7 @@
     EGLint directSPIRVGeneration                  = EGL_DONT_CARE;
     EGLint captureLimits                          = EGL_DONT_CARE;
     EGLint forceRobustResourceInit                = EGL_DONT_CARE;
+    EGLint directMetalGeneration                  = EGL_DONT_CARE;
 
     angle::PlatformMethods *platformMethods = nullptr;
 };
diff --git a/util/EGLWindow.cpp b/util/EGLWindow.cpp
index edf064b..8db658e 100644
--- a/util/EGLWindow.cpp
+++ b/util/EGLWindow.cpp
@@ -259,6 +259,11 @@
         enabledFeatureOverrides.push_back("directSPIRVGeneration");
     }
 
+    if (params.directMetalGeneration == EGL_TRUE)
+    {
+        enabledFeatureOverrides.push_back("directMetalGeneration");
+    }
+
     if (params.hasExplicitMemBarrierFeatureMtl == EGL_FALSE)
     {
         disabledFeatureOverrides.push_back("has_explicit_mem_barrier_mtl");