Add an ShPixelLocalStorageType enum

Adds ShPixelLocalStorageType to ShCompileOptionsPLS and adds a
getNativePixelLocalStorageType() call to ContextImpl. For now this enum
only tells the translater whether PLS formats needs to be packed into
r32 images, but it will soon also be able to select framebuffer fetch,
native pixel local storage, and other PLS implementations.

Bug: angleproject:7279
Change-Id: Ifbd419b20550b8711ae3044782177806796216f1
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3900498
Commit-Queue: Chris Dalton <chris@rive.app>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h
index 74cd318..dd0669f 100644
--- a/include/GLSLANG/ShaderLang.h
+++ b/include/GLSLANG/ShaderLang.h
@@ -26,7 +26,7 @@
 
 // Version number for shader translation API.
 // It is incremented every time the API changes.
-#define ANGLE_SH_VERSION 305
+#define ANGLE_SH_VERSION 306
 
 enum ShShaderSpec
 {
@@ -79,11 +79,20 @@
     SH_MSL_METAL_OUTPUT = 0x8B4D,
 };
 
+// For ANGLE_shader_pixel_local_storage.
+// Instructs the compiler which pixel local storage configuration to generate code for.
+enum class ShPixelLocalStorageType
+{
+    NotSupported,
+    ImageStoreR32PackedFormats,
+    ImageStoreNativeFormats,
+};
+
 // For ANGLE_shader_pixel_local_storage_coherent.
 // Instructs the compiler which fragment synchronization method to use, if any.
 enum class ShFragmentSynchronizationType
 {
-    NoSynchronization,
+    NotSupported,
 
     FragmentShaderInterlock_NV_GL,
     FragmentShaderOrdering_INTEL_GL,
@@ -110,8 +119,10 @@
 
 struct ShCompileOptionsPLS
 {
+    ShPixelLocalStorageType type = ShPixelLocalStorageType::NotSupported;
     // For ANGLE_shader_pixel_local_storage_coherent.
-    ShFragmentSynchronizationType fragmentSynchronizationType;
+    ShFragmentSynchronizationType fragmentSynchronizationType =
+        ShFragmentSynchronizationType::NotSupported;
 };
 
 struct ShCompileOptions
diff --git a/src/compiler/translator/tree_ops/RewritePixelLocalStorage.cpp b/src/compiler/translator/tree_ops/RewritePixelLocalStorage.cpp
index 2f6c411..34bc2d3 100644
--- a/src/compiler/translator/tree_ops/RewritePixelLocalStorage.cpp
+++ b/src/compiler/translator/tree_ops/RewritePixelLocalStorage.cpp
@@ -105,12 +105,10 @@
 class RewriteToImagesTraverser : public TIntermTraverser
 {
   public:
-    RewriteToImagesTraverser(TCompiler *compiler,
-                             TSymbolTable &symbolTable,
+    RewriteToImagesTraverser(TSymbolTable &symbolTable,
                              const ShCompileOptions &compileOptions,
                              int shaderVersion)
         : TIntermTraverser(true, false, false, &symbolTable),
-          mCompiler(compiler),
           mCompileOptions(&compileOptions),
           mShaderVersion(shaderVersion)
     {}
@@ -230,10 +228,7 @@
     // Do all PLS formats need to be packed into r32f, r32i, or r32ui image2Ds?
     bool needsR32Packing() const
     {
-        // ES images can only have both read and write access if their format is r32f, r32i, r32ui.
-        // D3D 11.0 UAVs only support R32_FLOAT, R32_UINT, R32_SINT formats.
-        return mCompiler->getOutputType() == ShShaderOutput::SH_ESSL_OUTPUT ||
-               mCompiler->getOutputType() == ShShaderOutput::SH_HLSL_4_1_OUTPUT;
+        return mCompileOptions->pls.type == ShPixelLocalStorageType::ImageStoreR32PackedFormats;
     }
 
     // Sets the given image2D as the backing storage for the plsSymbol's binding point. An entry
@@ -482,7 +477,6 @@
         return TIntermAggregate::CreateConstructor(imageStoreType, {result});
     }
 
-    const TCompiler *const mCompiler;
     const ShCompileOptions *const mCompileOptions;
     const int mShaderVersion;
 
@@ -533,7 +527,7 @@
     }
 
     // Rewrite PLS operations to image operations.
-    RewriteToImagesTraverser traverser(compiler, symbolTable, compileOptions, shaderVersion);
+    RewriteToImagesTraverser traverser(symbolTable, compileOptions, shaderVersion);
     root->traverse(&traverser);
     if (!traverser.updateTree(compiler, root))
     {
diff --git a/src/libANGLE/renderer/ContextImpl.h b/src/libANGLE/renderer/ContextImpl.h
index 608aa9a..3b167fe 100644
--- a/src/libANGLE/renderer/ContextImpl.h
+++ b/src/libANGLE/renderer/ContextImpl.h
@@ -212,10 +212,11 @@
     virtual angle::Result onUnMakeCurrent(const gl::Context *context);
 
     // Native capabilities, unmodified by gl::Context.
-    virtual gl::Caps getNativeCaps() const                         = 0;
-    virtual const gl::TextureCapsMap &getNativeTextureCaps() const = 0;
-    virtual const gl::Extensions &getNativeExtensions() const      = 0;
-    virtual const gl::Limitations &getNativeLimitations() const    = 0;
+    virtual gl::Caps getNativeCaps() const                                 = 0;
+    virtual const gl::TextureCapsMap &getNativeTextureCaps() const         = 0;
+    virtual const gl::Extensions &getNativeExtensions() const              = 0;
+    virtual const gl::Limitations &getNativeLimitations() const            = 0;
+    virtual ShPixelLocalStorageType getNativePixelLocalStorageType() const = 0;
 
     virtual angle::Result dispatchCompute(const gl::Context *context,
                                           GLuint numGroupsX,
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/libANGLE/renderer/d3d/RendererD3D.cpp
index edea121..39e6e53 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.cpp
+++ b/src/libANGLE/renderer/d3d/RendererD3D.cpp
@@ -152,6 +152,16 @@
     return mNativeLimitations;
 }
 
+ShPixelLocalStorageType RendererD3D::getNativePixelLocalStorageType() const
+{
+    if (!getNativeExtensions().shaderPixelLocalStorageANGLE)
+    {
+        return ShPixelLocalStorageType::NotSupported;
+    }
+    // Read/write UAVs only support "r32*" images.
+    return ShPixelLocalStorageType::ImageStoreR32PackedFormats;
+}
+
 Serial RendererD3D::generateSerial()
 {
     return mSerialFactory.generate();
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.h b/src/libANGLE/renderer/d3d/RendererD3D.h
index cdb57ea..3846e1e 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.h
+++ b/src/libANGLE/renderer/d3d/RendererD3D.h
@@ -424,6 +424,7 @@
     const gl::TextureCapsMap &getNativeTextureCaps() const;
     const gl::Extensions &getNativeExtensions() const;
     const gl::Limitations &getNativeLimitations() const;
+    ShPixelLocalStorageType getNativePixelLocalStorageType() const;
     virtual void initializeFrontendFeatures(angle::FrontendFeatures *features) const = 0;
 
     // Necessary hack for default framebuffers in D3D.
diff --git a/src/libANGLE/renderer/d3d/ShaderD3D.cpp b/src/libANGLE/renderer/d3d/ShaderD3D.cpp
index 8ada8f5..e08e478 100644
--- a/src/libANGLE/renderer/d3d/ShaderD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ShaderD3D.cpp
@@ -15,6 +15,7 @@
 #include "libANGLE/Context.h"
 #include "libANGLE/Shader.h"
 #include "libANGLE/features.h"
+#include "libANGLE/renderer/ContextImpl.h"
 #include "libANGLE/renderer/d3d/ProgramD3D.h"
 #include "libANGLE/renderer/d3d/RendererD3D.h"
 #include "libANGLE/trace.h"
@@ -286,10 +287,14 @@
     {
         options->initializeBuiltinsForInstancedMultiview = true;
     }
-    if (extensions.shaderPixelLocalStorageCoherentANGLE)
+    if (extensions.shaderPixelLocalStorageANGLE)
     {
-        options->pls.fragmentSynchronizationType =
-            ShFragmentSynchronizationType::RasterizerOrderViews_D3D;
+        options->pls.type = mRenderer->getNativePixelLocalStorageType();
+        if (extensions.shaderPixelLocalStorageCoherentANGLE)
+        {
+            options->pls.fragmentSynchronizationType =
+                ShFragmentSynchronizationType::RasterizerOrderViews_D3D;
+        }
     }
 
     auto postTranslateFunctor = [this](gl::ShCompilerInstance *compiler, std::string *infoLog) {
diff --git a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
index 3ccebf0..4c4b3ca 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
@@ -861,6 +861,11 @@
     return mRenderer->getNativeLimitations();
 }
 
+ShPixelLocalStorageType Context11::getNativePixelLocalStorageType() const
+{
+    return mRenderer->getNativePixelLocalStorageType();
+}
+
 angle::Result Context11::dispatchCompute(const gl::Context *context,
                                          GLuint numGroupsX,
                                          GLuint numGroupsY,
diff --git a/src/libANGLE/renderer/d3d/d3d11/Context11.h b/src/libANGLE/renderer/d3d/d3d11/Context11.h
index 90fd4fa..5f84e41 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Context11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Context11.h
@@ -232,6 +232,7 @@
     const gl::TextureCapsMap &getNativeTextureCaps() const override;
     const gl::Extensions &getNativeExtensions() const override;
     const gl::Limitations &getNativeLimitations() const override;
+    ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
 
     Renderer11 *getRenderer() const { return mRenderer; }
 
diff --git a/src/libANGLE/renderer/d3d/d3d9/Context9.cpp b/src/libANGLE/renderer/d3d/d3d9/Context9.cpp
index a4981cc..5f624e8 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Context9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Context9.cpp
@@ -466,6 +466,11 @@
     return mRenderer->getNativeLimitations();
 }
 
+ShPixelLocalStorageType Context9::getNativePixelLocalStorageType() const
+{
+    return mRenderer->getNativePixelLocalStorageType();
+}
+
 angle::Result Context9::dispatchCompute(const gl::Context *context,
                                         GLuint numGroupsX,
                                         GLuint numGroupsY,
diff --git a/src/libANGLE/renderer/d3d/d3d9/Context9.h b/src/libANGLE/renderer/d3d/d3d9/Context9.h
index 806569b..ce3e930 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Context9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/Context9.h
@@ -231,6 +231,7 @@
     const gl::TextureCapsMap &getNativeTextureCaps() const override;
     const gl::Extensions &getNativeExtensions() const override;
     const gl::Limitations &getNativeLimitations() const override;
+    ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
 
     angle::Result dispatchCompute(const gl::Context *context,
                                   GLuint numGroupsX,
diff --git a/src/libANGLE/renderer/gl/ContextGL.cpp b/src/libANGLE/renderer/gl/ContextGL.cpp
index 5895746..4979a6f 100644
--- a/src/libANGLE/renderer/gl/ContextGL.cpp
+++ b/src/libANGLE/renderer/gl/ContextGL.cpp
@@ -935,6 +935,11 @@
     return mRenderer->getNativeLimitations();
 }
 
+ShPixelLocalStorageType ContextGL::getNativePixelLocalStorageType() const
+{
+    return mRenderer->getNativePixelLocalStorageType();
+}
+
 StateManagerGL *ContextGL::getStateManager()
 {
     return mRenderer->getStateManager();
diff --git a/src/libANGLE/renderer/gl/ContextGL.h b/src/libANGLE/renderer/gl/ContextGL.h
index 1eefe4e..6916662 100644
--- a/src/libANGLE/renderer/gl/ContextGL.h
+++ b/src/libANGLE/renderer/gl/ContextGL.h
@@ -254,6 +254,7 @@
     const gl::TextureCapsMap &getNativeTextureCaps() const override;
     const gl::Extensions &getNativeExtensions() const override;
     const gl::Limitations &getNativeLimitations() const override;
+    ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
 
     // Handle helpers
     ANGLE_INLINE const FunctionsGL *getFunctions() const { return mRenderer->getFunctions(); }
diff --git a/src/libANGLE/renderer/gl/RendererGL.cpp b/src/libANGLE/renderer/gl/RendererGL.cpp
index 061ff55..6b60a06 100644
--- a/src/libANGLE/renderer/gl/RendererGL.cpp
+++ b/src/libANGLE/renderer/gl/RendererGL.cpp
@@ -331,6 +331,18 @@
     return mNativeLimitations;
 }
 
+ShPixelLocalStorageType RendererGL::getNativePixelLocalStorageType() const
+{
+    if (!getNativeExtensions().shaderPixelLocalStorageANGLE)
+    {
+        return ShPixelLocalStorageType::NotSupported;
+    }
+    // OpenGL ES only allows read/write access to "r32*" images.
+    return getFunctions()->standard == StandardGL::STANDARD_GL_ES
+               ? ShPixelLocalStorageType::ImageStoreR32PackedFormats
+               : ShPixelLocalStorageType::ImageStoreNativeFormats;
+}
+
 MultiviewImplementationTypeGL RendererGL::getMultiviewImplementationType() const
 {
     ensureCapsInitialized();
diff --git a/src/libANGLE/renderer/gl/RendererGL.h b/src/libANGLE/renderer/gl/RendererGL.h
index 4b2d469..d2a4ed9 100644
--- a/src/libANGLE/renderer/gl/RendererGL.h
+++ b/src/libANGLE/renderer/gl/RendererGL.h
@@ -111,6 +111,7 @@
     const gl::TextureCapsMap &getNativeTextureCaps() const;
     const gl::Extensions &getNativeExtensions() const;
     const gl::Limitations &getNativeLimitations() const;
+    ShPixelLocalStorageType getNativePixelLocalStorageType() const;
     void initializeFrontendFeatures(angle::FrontendFeatures *features) const;
 
     angle::Result dispatchCompute(const gl::Context *context,
diff --git a/src/libANGLE/renderer/gl/ShaderGL.cpp b/src/libANGLE/renderer/gl/ShaderGL.cpp
index bdde4e1..67c3529 100644
--- a/src/libANGLE/renderer/gl/ShaderGL.cpp
+++ b/src/libANGLE/renderer/gl/ShaderGL.cpp
@@ -11,6 +11,7 @@
 #include "common/debug.h"
 #include "libANGLE/Compiler.h"
 #include "libANGLE/Context.h"
+#include "libANGLE/renderer/ContextImpl.h"
 #include "libANGLE/renderer/gl/FunctionsGL.h"
 #include "libANGLE/renderer/gl/RendererGL.h"
 #include "libANGLE/trace.h"
@@ -375,39 +376,42 @@
         options->passHighpToPackUnormSnormBuiltins = true;
     }
 
-    if (mRenderer->getNativeExtensions().shaderPixelLocalStorageCoherentANGLE)
+    if (mRenderer->getNativeExtensions().shaderPixelLocalStorageANGLE)
     {
-        const ShShaderOutput translatorOutputType = GetShaderOutputType(GetFunctionsGL(context));
-
-        // Prefer vendor-specific extensions first. The PixelLocalStorageTest.Coherency test doesn't
-        // always pass on Intel when we use the ARB extension.
-        if (features.supportsFragmentShaderInterlockNV.enabled)
+        options->pls.type = mRenderer->getNativePixelLocalStorageType();
+        if (mRenderer->getNativeExtensions().shaderPixelLocalStorageCoherentANGLE)
         {
-            // This extension requires 430+. GetShaderOutputType() should always select 430+ on a GL
-            // 4.3 context, where this extension is defined.
-            ASSERT(mRenderer->getFunctions()->isAtLeastGL(gl::Version(4, 3)));
-            ASSERT(translatorOutputType >= SH_GLSL_430_CORE_OUTPUT);
-            options->pls.fragmentSynchronizationType =
-                ShFragmentSynchronizationType::FragmentShaderInterlock_NV_GL;
-        }
-        else if (features.supportsFragmentShaderOrderingINTEL.enabled)
-        {
-            // This extension requires 440+. GetShaderOutputType() should always select 440+ on a GL
-            // 4.4 context, where this extension is defined.
-            ASSERT(mRenderer->getFunctions()->isAtLeastGL(gl::Version(4, 4)));
-            ASSERT(translatorOutputType >= SH_GLSL_440_CORE_OUTPUT);
-            options->pls.fragmentSynchronizationType =
-                ShFragmentSynchronizationType::FragmentShaderOrdering_INTEL_GL;
-        }
-        else
-        {
-            ASSERT(features.supportsFragmentShaderInterlockARB.enabled);
-            // This extension requires 450+. GetShaderOutputType() should always select 450+ on a GL
-            // 4.5 context, where this extension is defined.
-            ASSERT(mRenderer->getFunctions()->isAtLeastGL(gl::Version(4, 5)));
-            ASSERT(translatorOutputType >= SH_GLSL_450_CORE_OUTPUT);
-            options->pls.fragmentSynchronizationType =
-                ShFragmentSynchronizationType::FragmentShaderInterlock_ARB_GL;
+            // Prefer vendor-specific extensions first. The PixelLocalStorageTest.Coherency test
+            // doesn't always pass on Intel when we use the ARB extension.
+            ShShaderOutput translatorOutputType = GetShaderOutputType(GetFunctionsGL(context));
+            if (features.supportsFragmentShaderInterlockNV.enabled)
+            {
+                // This extension requires 430+. GetShaderOutputType() should always select 430+ on
+                // a GL 4.3 context, where this extension is defined.
+                ASSERT(mRenderer->getFunctions()->isAtLeastGL(gl::Version(4, 3)));
+                ASSERT(translatorOutputType >= SH_GLSL_430_CORE_OUTPUT);
+                options->pls.fragmentSynchronizationType =
+                    ShFragmentSynchronizationType::FragmentShaderInterlock_NV_GL;
+            }
+            else if (features.supportsFragmentShaderOrderingINTEL.enabled)
+            {
+                // This extension requires 440+. GetShaderOutputType() should always select 440+ on
+                // a GL 4.4 context, where this extension is defined.
+                ASSERT(mRenderer->getFunctions()->isAtLeastGL(gl::Version(4, 4)));
+                ASSERT(translatorOutputType >= SH_GLSL_440_CORE_OUTPUT);
+                options->pls.fragmentSynchronizationType =
+                    ShFragmentSynchronizationType::FragmentShaderOrdering_INTEL_GL;
+            }
+            else
+            {
+                ASSERT(features.supportsFragmentShaderInterlockARB.enabled);
+                // This extension requires 450+. GetShaderOutputType() should always select 450+ on
+                // a GL 4.5 context, where this extension is defined.
+                ASSERT(mRenderer->getFunctions()->isAtLeastGL(gl::Version(4, 5)));
+                ASSERT(translatorOutputType >= SH_GLSL_450_CORE_OUTPUT);
+                options->pls.fragmentSynchronizationType =
+                    ShFragmentSynchronizationType::FragmentShaderInterlock_ARB_GL;
+            }
         }
     }
 
diff --git a/src/libANGLE/renderer/metal/ContextMtl.h b/src/libANGLE/renderer/metal/ContextMtl.h
index 67e137d..e437eab 100644
--- a/src/libANGLE/renderer/metal/ContextMtl.h
+++ b/src/libANGLE/renderer/metal/ContextMtl.h
@@ -207,6 +207,7 @@
     const gl::TextureCapsMap &getNativeTextureCaps() const override;
     const gl::Extensions &getNativeExtensions() const override;
     const gl::Limitations &getNativeLimitations() const override;
+    ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
 
     const ProgramMtl *getProgram() const { return mProgram; }
 
diff --git a/src/libANGLE/renderer/metal/ContextMtl.mm b/src/libANGLE/renderer/metal/ContextMtl.mm
index 23c1fba..6ce2331 100644
--- a/src/libANGLE/renderer/metal/ContextMtl.mm
+++ b/src/libANGLE/renderer/metal/ContextMtl.mm
@@ -1384,6 +1384,10 @@
 {
     return getDisplay()->getNativeLimitations();
 }
+ShPixelLocalStorageType ContextMtl::getNativePixelLocalStorageType() const
+{
+    return getDisplay()->getNativePixelLocalStorageType();
+}
 
 // Shader creation
 CompilerImpl *ContextMtl::createCompiler()
diff --git a/src/libANGLE/renderer/metal/DisplayMtl.h b/src/libANGLE/renderer/metal/DisplayMtl.h
index 3a657dd..aa0327b 100644
--- a/src/libANGLE/renderer/metal/DisplayMtl.h
+++ b/src/libANGLE/renderer/metal/DisplayMtl.h
@@ -120,6 +120,7 @@
     const gl::TextureCapsMap &getNativeTextureCaps() const;
     const gl::Extensions &getNativeExtensions() const;
     const gl::Limitations &getNativeLimitations() const;
+    ShPixelLocalStorageType getNativePixelLocalStorageType() const;
     const angle::FeaturesMtl &getFeatures() const { return mFeatures; }
 
     // Check whether either of the specified iOS or Mac GPU family is supported
diff --git a/src/libANGLE/renderer/metal/DisplayMtl.mm b/src/libANGLE/renderer/metal/DisplayMtl.mm
index b91d003..c3606ab 100644
--- a/src/libANGLE/renderer/metal/DisplayMtl.mm
+++ b/src/libANGLE/renderer/metal/DisplayMtl.mm
@@ -666,12 +666,16 @@
     ensureCapsInitialized();
     return mNativeExtensions;
 }
-
 const gl::Limitations &DisplayMtl::getNativeLimitations() const
 {
     ensureCapsInitialized();
     return mNativeLimitations;
 }
+ShPixelLocalStorageType DisplayMtl::getNativePixelLocalStorageType() const
+{
+    // PLS isn't supported on Metal yet.
+    return ShPixelLocalStorageType::NotSupported;
+}
 
 void DisplayMtl::ensureCapsInitialized() const
 {
diff --git a/src/libANGLE/renderer/null/ContextNULL.cpp b/src/libANGLE/renderer/null/ContextNULL.cpp
index f9e1b3e..a88250c 100644
--- a/src/libANGLE/renderer/null/ContextNULL.cpp
+++ b/src/libANGLE/renderer/null/ContextNULL.cpp
@@ -407,6 +407,13 @@
     return mLimitations;
 }
 
+ShPixelLocalStorageType ContextNULL::getNativePixelLocalStorageType() const
+{
+    return getNativeExtensions().shaderPixelLocalStorageANGLE
+               ? ShPixelLocalStorageType::ImageStoreNativeFormats
+               : ShPixelLocalStorageType::NotSupported;
+}
+
 CompilerImpl *ContextNULL::createCompiler()
 {
     return new CompilerNULL();
diff --git a/src/libANGLE/renderer/null/ContextNULL.h b/src/libANGLE/renderer/null/ContextNULL.h
index 630ff33..204ec06 100644
--- a/src/libANGLE/renderer/null/ContextNULL.h
+++ b/src/libANGLE/renderer/null/ContextNULL.h
@@ -201,6 +201,7 @@
     const gl::TextureCapsMap &getNativeTextureCaps() const override;
     const gl::Extensions &getNativeExtensions() const override;
     const gl::Limitations &getNativeLimitations() const override;
+    ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
 
     // Shader creation
     CompilerImpl *createCompiler() override;
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
index 1daa244..c16b936 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -5360,6 +5360,11 @@
     return mRenderer->getNativeLimitations();
 }
 
+ShPixelLocalStorageType ContextVk::getNativePixelLocalStorageType() const
+{
+    return mRenderer->getNativePixelLocalStorageType();
+}
+
 CompilerImpl *ContextVk::createCompiler()
 {
     return new CompilerVk();
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.h b/src/libANGLE/renderer/vulkan/ContextVk.h
index 97ef530..45e7989 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.h
+++ b/src/libANGLE/renderer/vulkan/ContextVk.h
@@ -329,6 +329,7 @@
     const gl::TextureCapsMap &getNativeTextureCaps() const override;
     const gl::Extensions &getNativeExtensions() const override;
     const gl::Limitations &getNativeLimitations() const override;
+    ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
 
     // Shader creation
     CompilerImpl *createCompiler() override;
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index e9925b3..6f814f1 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -4005,6 +4005,15 @@
     return mNativeLimitations;
 }
 
+ShPixelLocalStorageType RendererVk::getNativePixelLocalStorageType() const
+{
+    if (!getNativeExtensions().shaderPixelLocalStorageANGLE)
+    {
+        return ShPixelLocalStorageType::NotSupported;
+    }
+    return ShPixelLocalStorageType::ImageStoreNativeFormats;
+}
+
 void RendererVk::initializeFrontendFeatures(angle::FrontendFeatures *features) const
 {
     bool isSwiftShader =
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.h b/src/libANGLE/renderer/vulkan/RendererVk.h
index 0d56d85..fb96ee9 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.h
+++ b/src/libANGLE/renderer/vulkan/RendererVk.h
@@ -184,6 +184,7 @@
     const gl::TextureCapsMap &getNativeTextureCaps() const;
     const gl::Extensions &getNativeExtensions() const;
     const gl::Limitations &getNativeLimitations() const;
+    ShPixelLocalStorageType getNativePixelLocalStorageType() const;
     void initializeFrontendFeatures(angle::FrontendFeatures *features) const;
 
     uint32_t getQueueFamilyIndex() const { return mCurrentQueueFamilyIndex; }
diff --git a/src/libANGLE/renderer/vulkan/ShaderVk.cpp b/src/libANGLE/renderer/vulkan/ShaderVk.cpp
index e0926b0..87d6f45 100644
--- a/src/libANGLE/renderer/vulkan/ShaderVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ShaderVk.cpp
@@ -114,13 +114,17 @@
         options->precisionSafeDivision = true;
     }
 
-    if (contextVk->getExtensions().shaderPixelLocalStorageCoherentANGLE)
+    if (contextVk->getExtensions().shaderPixelLocalStorageANGLE)
     {
-        ASSERT(contextVk->getFeatures().supportsFragmentShaderPixelInterlock.enabled);
-        // GL_ARB_fragment_shader_interlock compiles to SPV_EXT_fragment_shader_interlock in both
-        // Vulkan GLSL and our own backend.
-        options->pls.fragmentSynchronizationType =
-            ShFragmentSynchronizationType::FragmentShaderInterlock_ARB_GL;
+        options->pls.type = contextVk->getNativePixelLocalStorageType();
+        if (contextVk->getExtensions().shaderPixelLocalStorageCoherentANGLE)
+        {
+            ASSERT(contextVk->getFeatures().supportsFragmentShaderPixelInterlock.enabled);
+            // GL_ARB_fragment_shader_interlock compiles to SPV_EXT_fragment_shader_interlock in
+            // both Vulkan Glslang and our own backend.
+            options->pls.fragmentSynchronizationType =
+                ShFragmentSynchronizationType::FragmentShaderInterlock_ARB_GL;
+        }
     }
 
     return compileImpl(context, compilerInstance, mState.getSource(), options);