Dawn/Native: Support SetImmediateData() in Pass Encoders

This CL add SetImmediateData() API to support user upload
immediate data in pass encoders.

Bug:366291600
Change-Id: I6e1e3129383a602baf448790e7837bcf4b5b5671
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/224954
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Shaobo Yan <shaoboyan@microsoft.com>
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index 4f627f9..13c02da 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -1022,6 +1022,14 @@
                 "args": [
                     {"name": "label", "type": "string view"}
                 ]
+            },
+            {
+                "name": "set immediate data",
+                "args": [
+                    {"name": "offset", "type": "uint32_t"},
+                    {"name": "data", "type": "void", "annotation": "const*", "length": "size"},
+                    {"name": "size", "type": "size_t"}
+                ]
             }
         ]
     },
@@ -2882,6 +2890,14 @@
                 "args": [
                     {"name": "label", "type": "string view"}
                 ]
+            },
+            {
+                "name": "set immediate data",
+                "args": [
+                    {"name": "offset", "type": "uint32_t"},
+                    {"name": "data", "type": "void", "annotation": "const*", "length": "size"},
+                    {"name": "size", "type": "size_t"}
+                ]
             }
         ]
     },
@@ -3180,6 +3196,14 @@
                 "args": [
                     {"name": "label", "type": "string view"}
                 ]
+            },
+            {
+                "name": "set immediate data",
+                "args": [
+                    {"name": "offset", "type": "uint32_t"},
+                    {"name": "data", "type": "void", "annotation": "const*", "length": "size"},
+                    {"name": "size", "type": "size_t"}
+                ]
             }
         ]
     },
diff --git a/src/dawn/dawn_wire.json b/src/dawn/dawn_wire.json
index 73b104c..ed464e3 100644
--- a/src/dawn/dawn_wire.json
+++ b/src/dawn/dawn_wire.json
@@ -122,6 +122,24 @@
             { "name": "device object handle", "type": "ObjectHandle", "handle_type": "device"},
             { "name": "device lost future", "type": "future" },
             { "name": "descriptor", "type": "device descriptor", "annotation": "const*" }
+        ],
+        "render pass encoder set immediate data": [
+            { "name": "render pass encoder id", "type": "ObjectId", "id_type": "render pass encoder"},
+            {"name": "offset", "type": "uint32_t"},
+            { "name": "data", "type": "uint8_t", "annotation": "const*", "length": "size", "wire_is_data_only": true},
+            { "name": "size", "type": "size_t"}
+        ],
+        "render bundle encoder set immediate data": [
+            { "name": "render bundle encoder id", "type": "ObjectId", "id_type": "render bundle encoder"},
+            {"name": "offset", "type": "uint32_t"},
+            { "name": "data", "type": "uint8_t", "annotation": "const*", "length": "size", "wire_is_data_only": true},
+            { "name": "size", "type": "size_t"}
+        ],
+        "compute pass encoder set immediate data": [
+            { "name": "compute pass encoder id", "type": "ObjectId", "id_type": "compute pass encoder"},
+            {"name": "offset", "type": "uint32_t"},
+            { "name": "data", "type": "uint8_t", "annotation": "const*", "length": "size", "wire_is_data_only": true},
+            { "name": "size", "type": "size_t"}
         ]
     },
     "return commands": {
@@ -259,7 +277,10 @@
             "TextureGetSampleCount",
             "TextureGetDimension",
             "TextureGetFormat",
-            "TextureGetUsage"
+            "TextureGetUsage",
+            "RenderPassEncoderSetImmediateData",
+            "RenderBundleEncoderSetImmediateData",
+            "ComputePassEncoderSetImmediateData"
         ],
         "client_handwritten_commands": [
             "AdapterGetInstance",
@@ -285,7 +306,10 @@
             "ShaderModule",
             "Surface",
             "SurfaceCapabilities",
-            "Texture"
+            "Texture",
+            "RenderPassEncoder",
+            "RenderBundleEncoder",
+            "ComputePassEncoder"
         ],
         "server_custom_pre_handler_commands": [
             "BufferDestroy",
diff --git a/src/dawn/native/Commands.cpp b/src/dawn/native/Commands.cpp
index 009388b..4021792 100644
--- a/src/dawn/native/Commands.cpp
+++ b/src/dawn/native/Commands.cpp
@@ -216,6 +216,14 @@
                 cmd->~SetBindGroupCmd();
                 break;
             }
+            case Command::SetImmediateData: {
+                SetImmediateDataCmd* cmd = commands->NextCommand<SetImmediateDataCmd>();
+                if (cmd->size > 0) {
+                    commands->NextData<uint8_t>(cmd->size);
+                }
+                cmd->~SetImmediateDataCmd();
+                break;
+            }
             case Command::SetIndexBuffer: {
                 SetIndexBufferCmd* cmd = commands->NextCommand<SetIndexBufferCmd>();
                 cmd->~SetIndexBufferCmd();
@@ -384,6 +392,14 @@
             break;
         }
 
+        case Command::SetImmediateData: {
+            SetImmediateDataCmd* cmd = commands->NextCommand<SetImmediateDataCmd>();
+            if (cmd->size > 0) {
+                commands->NextData<uint8_t>(cmd->size);
+            }
+            break;
+        }
+
         case Command::SetIndexBuffer:
             commands->NextCommand<SetIndexBufferCmd>();
             break;
@@ -483,6 +499,9 @@
 SetBindGroupCmd::SetBindGroupCmd() = default;
 SetBindGroupCmd::~SetBindGroupCmd() = default;
 
+SetImmediateDataCmd::SetImmediateDataCmd() = default;
+SetImmediateDataCmd::~SetImmediateDataCmd() = default;
+
 SetIndexBufferCmd::SetIndexBufferCmd() = default;
 SetIndexBufferCmd::~SetIndexBufferCmd() = default;
 
diff --git a/src/dawn/native/Commands.h b/src/dawn/native/Commands.h
index 9b5edbe..b7edeeb 100644
--- a/src/dawn/native/Commands.h
+++ b/src/dawn/native/Commands.h
@@ -83,6 +83,7 @@
     SetScissorRect,
     SetBlendConstant,
     SetBindGroup,
+    SetImmediateData,
     SetIndexBuffer,
     SetVertexBuffer,
     WriteBuffer,
@@ -366,6 +367,14 @@
     uint32_t dynamicOffsetCount;
 };
 
+struct SetImmediateDataCmd {
+    SetImmediateDataCmd();
+    ~SetImmediateDataCmd();
+
+    uint64_t offset;
+    uint64_t size;
+};
+
 struct SetIndexBufferCmd {
     SetIndexBufferCmd();
     ~SetIndexBufferCmd();
diff --git a/src/dawn/native/ProgrammableEncoder.cpp b/src/dawn/native/ProgrammableEncoder.cpp
index 0956226..c7a2352 100644
--- a/src/dawn/native/ProgrammableEncoder.cpp
+++ b/src/dawn/native/ProgrammableEncoder.cpp
@@ -116,6 +116,51 @@
         "encoding %s.PushDebugGroup(%s).", this, groupLabel);
 }
 
+void ProgrammableEncoder::APISetImmediateData(uint32_t offset, const void* data, size_t size) {
+    mEncodingContext->TryEncode(
+        this,
+        [&](CommandAllocator* allocator) -> MaybeError {
+            DAWN_INVALID_IF(!GetDevice()->HasFeature(Feature::ChromiumExperimentalImmediateData),
+                            "SetImmediateData() called without "
+                            "Feature::ChromiumExperimentalImmediateData supported.");
+
+            if (IsValidationEnabled()) {
+                uint32_t maxImmediateDataRangeByteSize =
+                    GetDevice()
+                        ->GetLimits()
+                        .experimentalImmediateDataLimits.maxImmediateDataRangeByteSize;
+                // Validate offset and size are aligned to 4 bytes.
+                DAWN_INVALID_IF(offset % 4 != 0, "offset (%u) is not a multiple of 4", offset);
+                DAWN_INVALID_IF(size % 4 != 0, "size (%u) is not a multiple of 4", size);
+
+                // Validate OOB
+                DAWN_INVALID_IF(offset > maxImmediateDataRangeByteSize,
+                                "offset (%u) is larger than maxImmediateDataRangeByteSize (%u).",
+                                offset, maxImmediateDataRangeByteSize);
+                DAWN_INVALID_IF(size > maxImmediateDataRangeByteSize,
+                                "size (%u) is larger than maxImmediateDataRangeByteSize (%u).",
+                                size, maxImmediateDataRangeByteSize);
+                DAWN_INVALID_IF(
+                    size > maxImmediateDataRangeByteSize - offset,
+                    "offset (%u) + size (%u): is larger than maxImmediateDataRangeByteSize (%u).",
+                    offset, size, maxImmediateDataRangeByteSize);
+            }
+
+            SetImmediateDataCmd* cmd =
+                allocator->Allocate<SetImmediateDataCmd>(Command::SetImmediateData);
+            cmd->offset = offset;
+            cmd->size = size;
+
+            if (size > 0) {
+                uint8_t* immediateDatas = allocator->AllocateData<uint8_t>(cmd->size);
+                memcpy(immediateDatas, data, size);
+            }
+
+            return {};
+        },
+        "encoding %s.SetImmediateData(%u, %u, ...).", this, offset, size);
+}
+
 MaybeError ProgrammableEncoder::ValidateSetBindGroup(BindGroupIndex index,
                                                      BindGroupBase* group,
                                                      uint32_t dynamicOffsetCountIn,
diff --git a/src/dawn/native/ProgrammableEncoder.h b/src/dawn/native/ProgrammableEncoder.h
index 600ac0e..9f37b0f 100644
--- a/src/dawn/native/ProgrammableEncoder.h
+++ b/src/dawn/native/ProgrammableEncoder.h
@@ -51,6 +51,7 @@
     void APIInsertDebugMarker(StringView groupLabel);
     void APIPopDebugGroup();
     void APIPushDebugGroup(StringView groupLabel);
+    void APISetImmediateData(uint32_t offset, const void* data, size_t size);
 
   protected:
     bool IsValidationEnabled() const;
diff --git a/src/dawn/native/d3d11/CommandBufferD3D11.cpp b/src/dawn/native/d3d11/CommandBufferD3D11.cpp
index d35d3ac..d9c8097 100644
--- a/src/dawn/native/d3d11/CommandBufferD3D11.cpp
+++ b/src/dawn/native/d3d11/CommandBufferD3D11.cpp
@@ -552,6 +552,9 @@
                 break;
             }
 
+            case Command::SetImmediateData:
+                return DAWN_UNIMPLEMENTED_ERROR("SetImmediateData unimplemented");
+
             default:
                 DAWN_UNREACHABLE();
         }
@@ -916,6 +919,9 @@
             case Command::WriteTimestamp:
                 return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented");
 
+            case Command::SetImmediateData:
+                return DAWN_UNIMPLEMENTED_ERROR("SetImmediateData unimplemented");
+
             default: {
                 DAWN_TRY(DoRenderBundleCommand(&mCommands, type));
             }
diff --git a/src/dawn/native/d3d12/CommandBufferD3D12.cpp b/src/dawn/native/d3d12/CommandBufferD3D12.cpp
index 1b99fcc..b0c1af7 100644
--- a/src/dawn/native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn/native/d3d12/CommandBufferD3D12.cpp
@@ -1344,6 +1344,9 @@
                 break;
             }
 
+            case Command::SetImmediateData:
+                return DAWN_UNIMPLEMENTED_ERROR("SetImmediateData unimplemented");
+
             default:
                 DAWN_UNREACHABLE();
         }
@@ -1870,6 +1873,9 @@
                 break;
             }
 
+            case Command::SetImmediateData:
+                return DAWN_UNIMPLEMENTED_ERROR("SetImmediateData unimplemented");
+
             default: {
                 DAWN_TRY(EncodeRenderBundleCommand(&mCommands, type));
                 break;
diff --git a/src/dawn/native/metal/CommandBufferMTL.mm b/src/dawn/native/metal/CommandBufferMTL.mm
index 749d007..b41d5e0 100644
--- a/src/dawn/native/metal/CommandBufferMTL.mm
+++ b/src/dawn/native/metal/CommandBufferMTL.mm
@@ -1454,6 +1454,9 @@
                 break;
             }
 
+            case Command::SetImmediateData:
+                return DAWN_UNIMPLEMENTED_ERROR("SetImmediateData unimplemented");
+
             default: {
                 DAWN_UNREACHABLE();
                 break;
@@ -1844,6 +1847,9 @@
                 break;
             }
 
+            case Command::SetImmediateData:
+                return DAWN_UNIMPLEMENTED_ERROR("SetImmediateData unimplemented");
+
             default: {
                 EncodeRenderBundleCommand(&mCommands, type);
                 break;
diff --git a/src/dawn/native/null/DeviceNull.cpp b/src/dawn/native/null/DeviceNull.cpp
index 9dd152c..f4d9059 100644
--- a/src/dawn/native/null/DeviceNull.cpp
+++ b/src/dawn/native/null/DeviceNull.cpp
@@ -92,7 +92,8 @@
     // Set the subgroups limit, as DeviceNull should support subgroups feature.
     limits->experimentalSubgroupLimits.minSubgroupSize = 4;
     limits->experimentalSubgroupLimits.maxSubgroupSize = 128;
-    limits->experimentalImmediateDataLimits.maxImmediateDataRangeByteSize = 16;
+    limits->experimentalImmediateDataLimits.maxImmediateDataRangeByteSize =
+        kMaxExternalImmediateConstantsPerPipeline * kImmediateConstantElementByteSize;
     return {};
 }
 
diff --git a/src/dawn/native/opengl/CommandBufferGL.cpp b/src/dawn/native/opengl/CommandBufferGL.cpp
index b99934c..4aad721 100644
--- a/src/dawn/native/opengl/CommandBufferGL.cpp
+++ b/src/dawn/native/opengl/CommandBufferGL.cpp
@@ -1016,6 +1016,9 @@
                 return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented");
             }
 
+            case Command::SetImmediateData:
+                return DAWN_UNIMPLEMENTED_ERROR("SetImmediateData unimplemented");
+
             default:
                 DAWN_UNREACHABLE();
         }
@@ -1402,6 +1405,9 @@
             case Command::WriteTimestamp:
                 return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented");
 
+            case Command::SetImmediateData:
+                return DAWN_UNIMPLEMENTED_ERROR("SetImmediateData unimplemented");
+
             default: {
                 DoRenderBundleCommand(&mCommands, type);
                 break;
diff --git a/src/dawn/native/vulkan/CommandBufferVk.cpp b/src/dawn/native/vulkan/CommandBufferVk.cpp
index 67d775f..f66d8a3 100644
--- a/src/dawn/native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn/native/vulkan/CommandBufferVk.cpp
@@ -1207,6 +1207,9 @@
                 break;
             }
 
+            case Command::SetImmediateData:
+                return DAWN_UNIMPLEMENTED_ERROR("SetImmediateData unimplemented");
+
             default:
                 DAWN_UNREACHABLE();
         }
@@ -1588,6 +1591,9 @@
                 break;
             }
 
+            case Command::SetImmediateData:
+                return DAWN_UNIMPLEMENTED_ERROR("SetImmediateData unimplemented");
+
             default: {
                 EncodeRenderBundleCommand(&mCommands, type);
                 break;
diff --git a/src/dawn/tests/unittests/validation/ImmediateDataTests.cpp b/src/dawn/tests/unittests/validation/ImmediateDataTests.cpp
index 9e8dcde..f9bdefb 100644
--- a/src/dawn/tests/unittests/validation/ImmediateDataTests.cpp
+++ b/src/dawn/tests/unittests/validation/ImmediateDataTests.cpp
@@ -25,6 +25,7 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include <cstdint>
 #include <limits>
 #include <string>
 #include <vector>
@@ -36,7 +37,6 @@
 namespace dawn {
 namespace {
 
-class PixelLocalStorageDisabledTest : public ValidationTest {};
 class ImmediateDataDisableTest : public ValidationTest {};
 
 // Check that creating a PipelineLayout with non-zero immediateDataRangeByteSize is disallowed
@@ -105,5 +105,113 @@
     }
 }
 
+// Check that SetImmediateData offset and length must be aligned to 4 bytes.
+TEST_F(ImmediateDataTest, ValidateSetImmediateDataAlignment) {
+    DAWN_SKIP_TEST_IF(!device.HasFeature(wgpu::FeatureName::ChromiumExperimentalImmediateData));
+
+    // Success cases
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        uint32_t data = 0;
+        wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
+        computePass.SetImmediateData(0, &data, 4);
+        computePass.End();
+        encoder.Finish();
+    }
+
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
+        computePass.SetImmediateData(4, nullptr, 0);
+        computePass.End();
+        encoder.Finish();
+    }
+
+    // Failed case with non-aligned offset bytes
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
+        computePass.SetImmediateData(2, nullptr, 0);
+        computePass.End();
+        ASSERT_DEVICE_ERROR(encoder.Finish());
+    }
+
+    // Failed cases with non-aligned size
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        uint8_t data = 0;
+        wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
+        computePass.SetImmediateData(0, &data, 2);
+        computePass.End();
+        ASSERT_DEVICE_ERROR(encoder.Finish());
+    }
+}
+
+// Check that SetImmediateData offset + length must be in bound.
+TEST_F(ImmediateDataTest, ValidateSetImmediateDataOOB) {
+    DAWN_SKIP_TEST_IF(!device.HasFeature(wgpu::FeatureName::ChromiumExperimentalImmediateData));
+
+    uint32_t maxImmediateDataRangeByteSize = GetMaxImmediateDataRangeByteSize();
+
+    // Success cases
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        std::vector<uint32_t> data(maxImmediateDataRangeByteSize / 4, 0);
+        wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
+        computePass.SetImmediateData(0, data.data(), maxImmediateDataRangeByteSize);
+        computePass.End();
+        encoder.Finish();
+    }
+
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
+        computePass.SetImmediateData(maxImmediateDataRangeByteSize, nullptr, 0);
+        computePass.End();
+        encoder.Finish();
+    }
+
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        uint32_t data = 0;
+        wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
+        computePass.SetImmediateData(maxImmediateDataRangeByteSize - 4, &data, 4);
+        computePass.End();
+        encoder.Finish();
+    }
+
+    // Failed case with offset oob
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        uint32_t offset = maxImmediateDataRangeByteSize + 4;
+        wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
+        computePass.SetImmediateData(offset, nullptr, 0);
+        computePass.End();
+        ASSERT_DEVICE_ERROR(encoder.Finish());
+    }
+
+    // Failed cases with size oob
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        uint32_t size = maxImmediateDataRangeByteSize + 4;
+        std::vector<uint32_t> data(size / 4, 0);
+        wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
+        computePass.SetImmediateData(0, data.data(), size);
+        computePass.End();
+        ASSERT_DEVICE_ERROR(encoder.Finish());
+    }
+
+    // Failed cases with offset + size oob
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        uint32_t offset = maxImmediateDataRangeByteSize;
+        uint32_t data[] = {0};
+        wgpu::ComputePassEncoder computePass = encoder.BeginComputePass();
+        computePass.SetImmediateData(offset, data, 4);
+        computePass.End();
+        ASSERT_DEVICE_ERROR(encoder.Finish());
+    }
+}
+
 }  // anonymous namespace
 }  // namespace dawn
diff --git a/src/dawn/wire/BUILD.gn b/src/dawn/wire/BUILD.gn
index fd5c870..1fddb75 100644
--- a/src/dawn/wire/BUILD.gn
+++ b/src/dawn/wire/BUILD.gn
@@ -113,6 +113,8 @@
     "client/Client.h",
     "client/ClientDoers.cpp",
     "client/ClientInlineMemoryTransferService.cpp",
+    "client/ComputePassEncoder.cpp",
+    "client/ComputePassEncoder.h",
     "client/Device.cpp",
     "client/Device.h",
     "client/EventManager.cpp",
@@ -129,6 +131,10 @@
     "client/QuerySet.h",
     "client/Queue.cpp",
     "client/Queue.h",
+    "client/RenderBundleEncoder.cpp",
+    "client/RenderBundleEncoder.h",
+    "client/RenderPassEncoder.cpp",
+    "client/RenderPassEncoder.h",
     "client/ShaderModule.cpp",
     "client/ShaderModule.h",
     "client/Surface.cpp",
@@ -143,6 +149,7 @@
     "server/ServerDevice.cpp",
     "server/ServerInlineMemoryTransferService.cpp",
     "server/ServerInstance.cpp",
+    "server/ServerProgrammableEncoder.cpp",
     "server/ServerQueue.cpp",
     "server/ServerShaderModule.cpp",
     "server/ServerSurface.cpp",
diff --git a/src/dawn/wire/CMakeLists.txt b/src/dawn/wire/CMakeLists.txt
index a5c17bc..a652770 100644
--- a/src/dawn/wire/CMakeLists.txt
+++ b/src/dawn/wire/CMakeLists.txt
@@ -48,6 +48,7 @@
     "client/Adapter.h"
     "client/ApiObjects.h"
     "client/Buffer.h"
+    "client/ComputePassEncoder.h"
     "client/Client.h"
     "client/Device.h"
     "client/EventManager.h"
@@ -57,6 +58,8 @@
     "client/ObjectStore.h"
     "client/QuerySet.h"
     "client/Queue.h"
+    "client/RenderBundleEncoder.h"
+    "client/RenderPassEncoder.h"
     "client/ShaderModule.h"
     "client/Surface.h"
     "client/Texture.h"
@@ -74,6 +77,7 @@
     "ChunkedCommandSerializer.cpp"
     "client/Adapter.cpp"
     "client/Buffer.cpp"
+    "client/ComputePassEncoder.cpp"
     "client/Client.cpp"
     "client/ClientDoers.cpp"
     "client/ClientInlineMemoryTransferService.cpp"
@@ -85,6 +89,8 @@
     "client/ObjectStore.cpp"
     "client/QuerySet.cpp"
     "client/Queue.cpp"
+    "client/RenderBundleEncoder.cpp"
+    "client/RenderPassEncoder.cpp"
     "client/ShaderModule.cpp"
     "client/Surface.cpp"
     "client/Texture.cpp"
@@ -95,6 +101,7 @@
     "server/ServerDevice.cpp"
     "server/ServerInlineMemoryTransferService.cpp"
     "server/ServerInstance.cpp"
+    "server/ServerProgrammableEncoder.cpp"
     "server/ServerQueue.cpp"
     "server/ServerShaderModule.cpp"
     "server/ServerSurface.cpp"
diff --git a/src/dawn/wire/client/ApiObjects.h b/src/dawn/wire/client/ApiObjects.h
index 7a71269..4d939a6 100644
--- a/src/dawn/wire/client/ApiObjects.h
+++ b/src/dawn/wire/client/ApiObjects.h
@@ -32,10 +32,13 @@
 
 #include "dawn/wire/client/Adapter.h"
 #include "dawn/wire/client/Buffer.h"
+#include "dawn/wire/client/ComputePassEncoder.h"
 #include "dawn/wire/client/Device.h"
 #include "dawn/wire/client/Instance.h"
 #include "dawn/wire/client/QuerySet.h"
 #include "dawn/wire/client/Queue.h"
+#include "dawn/wire/client/RenderBundleEncoder.h"
+#include "dawn/wire/client/RenderPassEncoder.h"
 #include "dawn/wire/client/ShaderModule.h"
 #include "dawn/wire/client/Surface.h"
 #include "dawn/wire/client/Texture.h"
diff --git a/src/dawn/wire/client/ComputePassEncoder.cpp b/src/dawn/wire/client/ComputePassEncoder.cpp
new file mode 100644
index 0000000..5681348
--- /dev/null
+++ b/src/dawn/wire/client/ComputePassEncoder.cpp
@@ -0,0 +1,50 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "dawn/wire/client/ComputePassEncoder.h"
+
+#include "dawn/wire/WireCmd_autogen.h"
+#include "dawn/wire/client/Client.h"
+
+namespace dawn::wire::client {
+ComputePassEncoder::~ComputePassEncoder() = default;
+
+ObjectType ComputePassEncoder::GetObjectType() const {
+    return ObjectType::ComputePassEncoder;
+}
+
+void ComputePassEncoder::SetImmediateData(uint32_t offset, const void* data, size_t size) {
+    ComputePassEncoderSetImmediateDataCmd cmd;
+    cmd.computePassEncoderId = GetWireId();
+    cmd.offset = offset;
+    cmd.data = static_cast<const uint8_t*>(data);
+    cmd.size = size;
+
+    GetClient()->SerializeCommand(cmd);
+}
+
+}  // namespace dawn::wire::client
diff --git a/src/dawn/wire/client/ComputePassEncoder.h b/src/dawn/wire/client/ComputePassEncoder.h
new file mode 100644
index 0000000..3563416
--- /dev/null
+++ b/src/dawn/wire/client/ComputePassEncoder.h
@@ -0,0 +1,50 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_DAWN_WIRE_CLIENT_COMPUTE_PASS_ENCODER_H_
+#define SRC_DAWN_WIRE_CLIENT_COMPUTE_PASS_ENCODER_H_
+
+#include <webgpu/webgpu.h>
+
+#include "dawn/wire/WireClient.h"
+#include "dawn/wire/client/ObjectBase.h"
+
+namespace dawn::wire::client {
+
+class ComputePassEncoder : public ObjectBase {
+  public:
+    using ObjectBase::ObjectBase;
+    ~ComputePassEncoder() override;
+    ObjectType GetObjectType() const override;
+
+    // DAWN API
+    void SetImmediateData(uint32_t offset, const void* data, size_t size);
+};
+
+}  // namespace dawn::wire::client
+
+#endif  // SRC_DAWN_WIRE_CLIENT_COMPUTE_PASS_ENCODER_H_
diff --git a/src/dawn/wire/client/RenderBundleEncoder.cpp b/src/dawn/wire/client/RenderBundleEncoder.cpp
new file mode 100644
index 0000000..54e6da0
--- /dev/null
+++ b/src/dawn/wire/client/RenderBundleEncoder.cpp
@@ -0,0 +1,50 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "dawn/wire/client/RenderBundleEncoder.h"
+
+#include "dawn/wire/WireCmd_autogen.h"
+#include "dawn/wire/client/Client.h"
+
+namespace dawn::wire::client {
+RenderBundleEncoder::~RenderBundleEncoder() = default;
+
+ObjectType RenderBundleEncoder::GetObjectType() const {
+    return ObjectType::RenderBundleEncoder;
+}
+
+void RenderBundleEncoder::SetImmediateData(uint32_t offset, const void* data, size_t size) {
+    RenderBundleEncoderSetImmediateDataCmd cmd;
+    cmd.renderBundleEncoderId = GetWireId();
+    cmd.offset = offset;
+    cmd.data = static_cast<const uint8_t*>(data);
+    cmd.size = size;
+
+    GetClient()->SerializeCommand(cmd);
+}
+
+}  // namespace dawn::wire::client
diff --git a/src/dawn/wire/client/RenderBundleEncoder.h b/src/dawn/wire/client/RenderBundleEncoder.h
new file mode 100644
index 0000000..7ce53b8
--- /dev/null
+++ b/src/dawn/wire/client/RenderBundleEncoder.h
@@ -0,0 +1,50 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_DAWN_WIRE_CLIENT_RENDER_BUNDLE_ENCODER_H_
+#define SRC_DAWN_WIRE_CLIENT_RENDER_BUNDLE_ENCODER_H_
+
+#include <webgpu/webgpu.h>
+
+#include "dawn/wire/WireClient.h"
+#include "dawn/wire/client/ObjectBase.h"
+
+namespace dawn::wire::client {
+
+class RenderBundleEncoder : public ObjectBase {
+  public:
+    using ObjectBase::ObjectBase;
+    ~RenderBundleEncoder() override;
+    ObjectType GetObjectType() const override;
+
+    // DAWN API
+    void SetImmediateData(uint32_t offset, const void* data, size_t size);
+};
+
+}  // namespace dawn::wire::client
+
+#endif  // SRC_DAWN_WIRE_CLIENT_RENDER_BUNDLE_ENCODER_H_
diff --git a/src/dawn/wire/client/RenderPassEncoder.cpp b/src/dawn/wire/client/RenderPassEncoder.cpp
new file mode 100644
index 0000000..4c9d61e
--- /dev/null
+++ b/src/dawn/wire/client/RenderPassEncoder.cpp
@@ -0,0 +1,50 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "dawn/wire/client/RenderPassEncoder.h"
+
+#include "dawn/wire/WireCmd_autogen.h"
+#include "dawn/wire/client/Client.h"
+
+namespace dawn::wire::client {
+RenderPassEncoder::~RenderPassEncoder() = default;
+
+ObjectType RenderPassEncoder::GetObjectType() const {
+    return ObjectType::RenderPassEncoder;
+}
+
+void RenderPassEncoder::SetImmediateData(uint32_t offset, const void* data, size_t size) {
+    RenderPassEncoderSetImmediateDataCmd cmd;
+    cmd.renderPassEncoderId = GetWireId();
+    cmd.offset = offset;
+    cmd.data = static_cast<const uint8_t*>(data);
+    cmd.size = size;
+
+    GetClient()->SerializeCommand(cmd);
+}
+
+}  // namespace dawn::wire::client
diff --git a/src/dawn/wire/client/RenderPassEncoder.h b/src/dawn/wire/client/RenderPassEncoder.h
new file mode 100644
index 0000000..e52ee42
--- /dev/null
+++ b/src/dawn/wire/client/RenderPassEncoder.h
@@ -0,0 +1,50 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_DAWN_WIRE_CLIENT_RENDER_PASS_ENCODER_H_
+#define SRC_DAWN_WIRE_CLIENT_RENDER_PASS_ENCODER_H_
+
+#include <webgpu/webgpu.h>
+
+#include "dawn/wire/WireClient.h"
+#include "dawn/wire/client/ObjectBase.h"
+
+namespace dawn::wire::client {
+
+class RenderPassEncoder : public ObjectBase {
+  public:
+    using ObjectBase::ObjectBase;
+    ~RenderPassEncoder() override;
+    ObjectType GetObjectType() const override;
+
+    // DAWN API
+    void SetImmediateData(uint32_t offset, const void* data, size_t size);
+};
+
+}  // namespace dawn::wire::client
+
+#endif  // SRC_DAWN_WIRE_CLIENT_RENDER_PASS_ENCODER_H_
diff --git a/src/dawn/wire/server/ServerProgrammableEncoder.cpp b/src/dawn/wire/server/ServerProgrammableEncoder.cpp
new file mode 100644
index 0000000..1d4cc55
--- /dev/null
+++ b/src/dawn/wire/server/ServerProgrammableEncoder.cpp
@@ -0,0 +1,65 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <limits>
+
+#include "dawn/common/Assert.h"
+#include "dawn/wire/server/Server.h"
+
+namespace dawn::wire::server {
+
+WireResult Server::DoRenderPassEncoderSetImmediateData(
+    Known<WGPURenderPassEncoder> renderPassEncoder,
+    uint32_t immediateDataRangeOffsetBytes,
+    const uint8_t* data,
+    size_t size) {
+    mProcs.renderPassEncoderSetImmediateData(renderPassEncoder->handle,
+                                             immediateDataRangeOffsetBytes, data, size);
+    return WireResult::Success;
+}
+
+WireResult Server::DoRenderBundleEncoderSetImmediateData(
+    Known<WGPURenderBundleEncoder> renderBundleEncoder,
+    uint32_t immediateDataRangeOffsetBytes,
+    const uint8_t* data,
+    size_t size) {
+    mProcs.renderBundleEncoderSetImmediateData(renderBundleEncoder->handle,
+                                               immediateDataRangeOffsetBytes, data, size);
+    return WireResult::Success;
+}
+
+WireResult Server::DoComputePassEncoderSetImmediateData(
+    Known<WGPUComputePassEncoder> computePassEncoder,
+    uint32_t immediateDataRangeOffsetBytes,
+    const uint8_t* data,
+    size_t size) {
+    mProcs.computePassEncoderSetImmediateData(computePassEncoder->handle,
+                                              immediateDataRangeOffsetBytes, data, size);
+    return WireResult::Success;
+}
+
+}  // namespace dawn::wire::server