WebGPU: Allow null bind group layout in `GPUPipelineLayoutDescriptor`

This patch allows creating pipeline layout with null bind group
layout in Blink to align with the latest WebGPU SPEC. Note that
currently creating pipeline layout with null bind group layout is
only allowed with the command line parameter "--enable-unsafe-webgpu".

Bug: chromium:377836524
Change-Id: If91879e579e17d0d5adc6e09c2481cd2ef077d56
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6040772
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Fernando Serboncini <fserb@chromium.org>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1388450}
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
index 8d4c69a..808715fc 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -566,8 +566,9 @@
 }
 
 GPUPipelineLayout* GPUDevice::createPipelineLayout(
+    ScriptState* script_state,
     const GPUPipelineLayoutDescriptor* descriptor) {
-  return GPUPipelineLayout::Create(this, descriptor);
+  return GPUPipelineLayout::Create(script_state, this, descriptor);
 }
 
 GPUShaderModule* GPUDevice::createShaderModule(
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.h b/third_party/blink/renderer/modules/webgpu/gpu_device.h
index 52a9a5a..cfb5c8c 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.h
@@ -128,6 +128,7 @@
       const GPUBindGroupLayoutDescriptor* descriptor,
       ExceptionState& exception_state);
   GPUPipelineLayout* createPipelineLayout(
+      ScriptState* script_state,
       const GPUPipelineLayoutDescriptor* descriptor);
 
   GPUShaderModule* createShaderModule(
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.idl b/third_party/blink/renderer/modules/webgpu/gpu_device.idl
index e84315b..afbf383 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.idl
@@ -25,7 +25,7 @@
 
     [RaisesException] GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
     [RaisesException] GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
-    GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
+    [CallWith=ScriptState] GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
 
     GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
     [CallWith=ScriptState] GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.cc b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.cc
index e710120..7392226 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.cc
@@ -8,21 +8,39 @@
 #include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
 
 namespace blink {
 
 // static
 GPUPipelineLayout* GPUPipelineLayout::Create(
+    ScriptState* script_state,
     GPUDevice* device,
     const GPUPipelineLayoutDescriptor* webgpu_desc) {
   DCHECK(device);
   DCHECK(webgpu_desc);
 
+  v8::Isolate* isolate = script_state->GetIsolate();
   size_t bind_group_layout_count = webgpu_desc->bindGroupLayouts().size();
 
   std::unique_ptr<wgpu::BindGroupLayout[]> bind_group_layouts =
       bind_group_layout_count != 0 ? AsDawnType(webgpu_desc->bindGroupLayouts())
                                    : nullptr;
+  // TODO(crbug.com/377836524): Remove WebGPUAllowNullInPipelineLayoutEntries
+  // and the check here once the feature is safely landed.
+  if (!RuntimeEnabledFeatures::
+          WebGPUAllowNullInPipelineLayoutEntriesEnabled()) {
+    for (const auto& bind_group_layout : webgpu_desc->bindGroupLayouts()) {
+      if (bind_group_layout == nullptr) {
+        ExceptionState exception_state(isolate);
+        exception_state.ThrowTypeError(
+            "Null bind group layout in PipelineLayoutDescriptor requires the "
+            "WebGPUAllowNullInPipelineLayoutEntries Blink feature.");
+        return nullptr;
+      }
+    }
+  }
 
   wgpu::PipelineLayoutDescriptor dawn_desc = {
       .bindGroupLayoutCount = bind_group_layout_count,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h
index 9a68f8d..abb6ed1a 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h
@@ -10,12 +10,14 @@
 namespace blink {
 
 class GPUPipelineLayoutDescriptor;
+class ScriptState;
 
 class GPUPipelineLayout : public DawnObject<wgpu::PipelineLayout> {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
   static GPUPipelineLayout* Create(
+      ScriptState* script_state,
       GPUDevice* device,
       const GPUPipelineLayoutDescriptor* webgpu_desc);
   explicit GPUPipelineLayout(GPUDevice* device,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout_descriptor.idl
index 75ed2d1..23901d3 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout_descriptor.idl
@@ -5,5 +5,5 @@
 // https://gpuweb.github.io/gpuweb/
 
 dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase {
-    required sequence<GPUBindGroupLayout> bindGroupLayouts;
+    required sequence<GPUBindGroupLayout?> bindGroupLayouts;
 };
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index f8405e6..e586d94c 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -4773,6 +4773,14 @@
       public: true,
     },
     {
+      // Launch feature flag to allow null bind group layouts in
+      // GPUPipelineLayoutDescriptor.
+      name: "WebGPUAllowNullInPipelineLayoutEntries",
+      status: "experimental",
+      // Also enabled as part of all experimental WebGPU features.
+      implied_by: ["WebGPUExperimentalFeatures"],
+    },
+    {
       // WebGPU developer features are deliberately not enabled by experimental
       // web platform features.
       name: "WebGPUDeveloperFeatures",