Add Overrides implementation for OpenGL/OpenGLES backend

As we are using SubstituteOverride, it is easy to add
overridable constants support for OpenGL/OpenGLES.

Also add validate workgroup size for null backend.

Bug: dawn:1537, dawn:1504
Change-Id: I293f10b9a6c606aee6c0ed25b1d966bc56a0b88d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/101800
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Shrek Shao <shrekshao@google.com>
diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
index f67167e..a5392a1 100644
--- a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
+++ b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
@@ -327,8 +327,8 @@
     }
 
     if (r.substituteOverrideConfig) {
-        // This needs to run after SingleEntryPoint transform to get rid of overrides not used for
-        // the current entry point.
+        // This needs to run after SingleEntryPoint transform which removes unused overrides for
+        // current entry point.
         transformManager.Add<tint::transform::SubstituteOverride>();
         transformInputs.Add<tint::transform::SubstituteOverride::Config>(
             std::move(r.substituteOverrideConfig).value());
diff --git a/src/dawn/native/metal/ShaderModuleMTL.mm b/src/dawn/native/metal/ShaderModuleMTL.mm
index b0f59a3..e07cd1d 100644
--- a/src/dawn/native/metal/ShaderModuleMTL.mm
+++ b/src/dawn/native/metal/ShaderModuleMTL.mm
@@ -206,8 +206,8 @@
             }
 
             if (r.substituteOverrideConfig) {
-                // This needs to run after SingleEntryPoint transform to get rid of overrides not
-                // used for the current entry point.
+                // This needs to run after SingleEntryPoint transform which removes unused overrides
+                // for current entry point.
                 transformManager.Add<tint::transform::SubstituteOverride>();
                 transformInputs.Add<tint::transform::SubstituteOverride::Config>(
                     std::move(r.substituteOverrideConfig).value());
diff --git a/src/dawn/native/null/DeviceNull.cpp b/src/dawn/native/null/DeviceNull.cpp
index 79d5f66..badb570 100644
--- a/src/dawn/native/null/DeviceNull.cpp
+++ b/src/dawn/native/null/DeviceNull.cpp
@@ -22,6 +22,9 @@
 #include "dawn/native/ErrorData.h"
 #include "dawn/native/Instance.h"
 #include "dawn/native/Surface.h"
+#include "dawn/native/TintUtils.h"
+
+#include "tint/tint.h"
 
 namespace dawn::native::null {
 
@@ -383,6 +386,40 @@
 
 // ComputePipeline
 MaybeError ComputePipeline::Initialize() {
+    const ProgrammableStage& computeStage = GetStage(SingleShaderStage::Compute);
+
+    tint::Program transformedProgram;
+    const tint::Program* program;
+    if (!computeStage.metadata->overrides.empty()) {
+        tint::transform::Manager transformManager;
+        tint::transform::DataMap transformInputs;
+
+        transformManager.Add<tint::transform::SingleEntryPoint>();
+        transformInputs.Add<tint::transform::SingleEntryPoint::Config>(
+            computeStage.entryPoint.c_str());
+
+        // This needs to run after SingleEntryPoint transform which removes unused overrides for
+        // current entry point.
+        transformManager.Add<tint::transform::SubstituteOverride>();
+        transformInputs.Add<tint::transform::SubstituteOverride::Config>(
+            BuildSubstituteOverridesTransformConfig(computeStage));
+
+        DAWN_TRY_ASSIGN(transformedProgram,
+                        RunTransforms(&transformManager, computeStage.module->GetTintProgram(),
+                                      transformInputs, nullptr, nullptr));
+
+        program = &transformedProgram;
+    } else {
+        program = computeStage.module->GetTintProgram();
+    }
+
+    // Do the workgroup size validation as it is actually backend agnostic.
+    const CombinedLimits& limits = GetDevice()->GetLimits();
+    Extent3D _;
+    DAWN_TRY_ASSIGN(
+        _, ValidateComputeStageWorkgroupSize(*program, computeStage.entryPoint.c_str(),
+                                             LimitsForCompilationRequest::Create(limits.v1)));
+
     return {};
 }
 
diff --git a/src/dawn/native/opengl/ShaderModuleGL.cpp b/src/dawn/native/opengl/ShaderModuleGL.cpp
index 172d401..caaf863 100644
--- a/src/dawn/native/opengl/ShaderModuleGL.cpp
+++ b/src/dawn/native/opengl/ShaderModuleGL.cpp
@@ -57,13 +57,16 @@
 
 using BindingMap = std::unordered_map<tint::sem::BindingPoint, tint::sem::BindingPoint>;
 
-#define GLSL_COMPILATION_REQUEST_MEMBERS(X)                                              \
-    X(const tint::Program*, inputProgram)                                                \
-    X(std::string, entryPointName)                                                       \
-    X(tint::transform::MultiplanarExternalTexture::BindingsMap, externalTextureBindings) \
-    X(BindingMap, glBindings)                                                            \
-    X(opengl::OpenGLVersion::Standard, glVersionStandard)                                \
-    X(uint32_t, glVersionMajor)                                                          \
+#define GLSL_COMPILATION_REQUEST_MEMBERS(X)                                                 \
+    X(const tint::Program*, inputProgram)                                                   \
+    X(std::string, entryPointName)                                                          \
+    X(SingleShaderStage, stage)                                                             \
+    X(tint::transform::MultiplanarExternalTexture::BindingsMap, externalTextureBindings)    \
+    X(BindingMap, glBindings)                                                               \
+    X(std::optional<tint::transform::SubstituteOverride::Config>, substituteOverrideConfig) \
+    X(LimitsForCompilationRequest, limits)                                                  \
+    X(opengl::OpenGLVersion::Standard, glVersionStandard)                                   \
+    X(uint32_t, glVersionMajor)                                                             \
     X(uint32_t, glVersionMinor)
 
 DAWN_MAKE_CACHE_REQUEST(GLSLCompilationRequest, GLSL_COMPILATION_REQUEST_MEMBERS);
@@ -168,11 +171,21 @@
         }
     }
 
+    std::optional<tint::transform::SubstituteOverride::Config> substituteOverrideConfig;
+    if (!programmableStage.metadata->overrides.empty()) {
+        substituteOverrideConfig = BuildSubstituteOverridesTransformConfig(programmableStage);
+    }
+
+    const CombinedLimits& limits = GetDevice()->GetLimits();
+
     GLSLCompilationRequest req = {};
     req.inputProgram = GetTintProgram();
+    req.stage = stage;
     req.entryPointName = programmableStage.entryPoint;
     req.externalTextureBindings = BuildExternalTextureTransformBindings(layout);
     req.glBindings = std::move(glBindings);
+    req.substituteOverrideConfig = std::move(substituteOverrideConfig);
+    req.limits = LimitsForCompilationRequest::Create(limits.v1);
     req.glVersionStandard = version.GetStandard();
     req.glVersionMajor = version.GetMajor();
     req.glVersionMinor = version.GetMinor();
@@ -190,10 +203,27 @@
                     std::move(r.externalTextureBindings));
             }
 
+            if (r.substituteOverrideConfig) {
+                transformManager.Add<tint::transform::SingleEntryPoint>();
+                transformInputs.Add<tint::transform::SingleEntryPoint::Config>(r.entryPointName);
+                // This needs to run after SingleEntryPoint transform which removes unused overrides
+                // for current entry point.
+                transformManager.Add<tint::transform::SubstituteOverride>();
+                transformInputs.Add<tint::transform::SubstituteOverride::Config>(
+                    std::move(r.substituteOverrideConfig).value());
+            }
+
             tint::Program program;
             DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, r.inputProgram,
                                                    transformInputs, nullptr, nullptr));
 
+            if (r.stage == SingleShaderStage::Compute) {
+                // Validate workgroup size after program runs transforms.
+                Extent3D _;
+                DAWN_TRY_ASSIGN(_, ValidateComputeStageWorkgroupSize(
+                                       program, r.entryPointName.c_str(), r.limits));
+            }
+
             tint::writer::glsl::Options tintOptions;
             tintOptions.version = tint::writer::glsl::Version(ToTintGLStandard(r.glVersionStandard),
                                                               r.glVersionMajor, r.glVersionMinor);
diff --git a/src/dawn/native/vulkan/ShaderModuleVk.cpp b/src/dawn/native/vulkan/ShaderModuleVk.cpp
index 6588627..0ec0092 100644
--- a/src/dawn/native/vulkan/ShaderModuleVk.cpp
+++ b/src/dawn/native/vulkan/ShaderModuleVk.cpp
@@ -311,8 +311,8 @@
                     r.newBindingsMap);
             }
             if (r.substituteOverrideConfig) {
-                // This needs to run after SingleEntryPoint transform to get rid of overrides not
-                // used for the current entry point.
+                // This needs to run after SingleEntryPoint transform which removes unused overrides
+                // for current entry point.
                 transformManager.Add<tint::transform::SubstituteOverride>();
                 transformInputs.Add<tint::transform::SubstituteOverride::Config>(
                     std::move(r.substituteOverrideConfig).value());
diff --git a/src/dawn/tests/end2end/ShaderTests.cpp b/src/dawn/tests/end2end/ShaderTests.cpp
index 45ba077..3ce2759 100644
--- a/src/dawn/tests/end2end/ShaderTests.cpp
+++ b/src/dawn/tests/end2end/ShaderTests.cpp
@@ -395,9 +395,6 @@
 
 // Test overridable constants without numeric identifiers
 TEST_P(ShaderTests, OverridableConstants) {
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
-
     uint32_t const kCount = 11;
     std::vector<uint32_t> expected(kCount);
     std::iota(expected.begin(), expected.end(), 0);
@@ -473,9 +470,6 @@
 
 // Test one shader shared by two pipelines with different constants overridden
 TEST_P(ShaderTests, OverridableConstantsSharedShader) {
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
-
     std::vector<uint32_t> expected1{1};
     wgpu::Buffer buffer1 = CreateBuffer(expected1.size());
     std::vector<uint32_t> expected2{2};
@@ -530,9 +524,6 @@
 
 // Test overridable constants work with workgroup size
 TEST_P(ShaderTests, OverridableConstantsWorkgroupSize) {
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
-
     std::string shader = R"(
 override x: u32;
 
@@ -594,9 +585,6 @@
 
 // Test overridable constants with numeric identifiers
 TEST_P(ShaderTests, OverridableConstantsNumericIdentifiers) {
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
-
     uint32_t const kCount = 4;
     std::vector<uint32_t> expected{1u, 2u, 3u, 0u};
     wgpu::Buffer buffer = CreateBuffer(kCount);
@@ -651,9 +639,6 @@
 // Test overridable constants precision
 // D3D12 HLSL shader uses defines so we want float number to have enough precision
 TEST_P(ShaderTests, OverridableConstantsPrecision) {
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
-
     uint32_t const kCount = 2;
     float const kValue1 = 3.14159;
     float const kValue2 = 3.141592653589793238;
@@ -702,9 +687,6 @@
 
 // Test overridable constants for different entry points
 TEST_P(ShaderTests, OverridableConstantsMultipleEntryPoints) {
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
-
     uint32_t const kCount = 1;
     std::vector<uint32_t> expected1{1u};
     std::vector<uint32_t> expected2{2u};
@@ -807,9 +789,6 @@
 // Draw a triangle covering the render target, with vertex position and color values from
 // overridable constants
 TEST_P(ShaderTests, OverridableConstantsRenderPipeline) {
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
-    DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
-
     wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
 @id(1111) override xright: f32;
 @id(2222) override ytop: f32;
diff --git a/src/dawn/tests/end2end/ShaderValidationTests.cpp b/src/dawn/tests/end2end/ShaderValidationTests.cpp
index c8b03f3..e2e4365 100644
--- a/src/dawn/tests/end2end/ShaderValidationTests.cpp
+++ b/src/dawn/tests/end2end/ShaderValidationTests.cpp
@@ -392,4 +392,10 @@
     CheckPipelineWithWorkgroupStorage(false, 0, maxMat4Count + 1);
 }
 
-DAWN_INSTANTIATE_TEST(WorkgroupSizeValidationTest, D3D12Backend(), MetalBackend(), VulkanBackend());
+DAWN_INSTANTIATE_TEST(WorkgroupSizeValidationTest,
+                      D3D12Backend(),
+                      MetalBackend(),
+                      NullBackend(),
+                      OpenGLBackend(),
+                      OpenGLESBackend(),
+                      VulkanBackend());
diff --git a/src/dawn/tests/unittests/validation/OverridableConstantsValidationTests.cpp b/src/dawn/tests/unittests/validation/OverridableConstantsValidationTests.cpp
index 882bf25..c0f9eec 100644
--- a/src/dawn/tests/unittests/validation/OverridableConstantsValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/OverridableConstantsValidationTests.cpp
@@ -120,6 +120,11 @@
         TestCreatePipeline(constants);
     }
     {
+        // Error: c10 already has a constant numeric id specified
+        std::vector<wgpu::ConstantEntry> constants{{nullptr, "c10", 0}};
+        ASSERT_DEVICE_ERROR(TestCreatePipeline(constants));
+    }
+    {
         // Error: constant numeric id not specified
         std::vector<wgpu::ConstantEntry> constants{{nullptr, "9999", 0}};
         ASSERT_DEVICE_ERROR(TestCreatePipeline(constants));