Remove RenderPassDescriptorBuilder

This patch removes RenderPassDescriptorBuilder completely from Dawn.
With this patch, RenderPassDescriptor is a structure instead of a Dawn
object, and all the checks in RenderPassDescriptorBuilder are moved into
CommandEncoder.cpp.

This patch also updates the helper functions and structures related to
RenderPassDescriptor because RenderPassDescriptor is no longer an
object but a structure with members in pointers.

BUG=dawn:6

Change-Id: Ic6d015582031891f35ffef912f0e460a9c010f81
Reviewed-on: https://dawn-review.googlesource.com/c/4902
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 7086b65..1bdeb3e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -483,8 +483,6 @@
     "src/dawn_native/Queue.h",
     "src/dawn_native/RefCounted.cpp",
     "src/dawn_native/RefCounted.h",
-    "src/dawn_native/RenderPassDescriptor.cpp",
-    "src/dawn_native/RenderPassDescriptor.h",
     "src/dawn_native/RenderPassEncoder.cpp",
     "src/dawn_native/RenderPassEncoder.h",
     "src/dawn_native/RenderPipeline.cpp",
diff --git a/dawn.json b/dawn.json
index d1618ff..cb5e83a 100644
--- a/dawn.json
+++ b/dawn.json
@@ -285,7 +285,7 @@
             {
                 "name": "begin render pass",
                 "args": [
-                    {"name": "info", "type": "render pass descriptor"}
+                    {"name": "info", "type": "render pass descriptor", "annotation": "const*"}
                 ],
                 "returns": "render pass encoder"
             },
@@ -444,10 +444,6 @@
                 ]
             },
             {
-                "name": "create render pass descriptor builder",
-                "returns": "render pass descriptor builder"
-            },
-            {
                 "name": "create input state builder",
                 "returns": "input state builder"
             },
@@ -746,31 +742,13 @@
         ]
     },
 
-    "render pass descriptor builder": {
-        "category": "object",
-        "methods": [
-            {
-                "name": "get result",
-                "returns": "render pass descriptor"
-            },
-            {
-                "name": "set color attachments",
-                "args": [
-                    {"name": "count", "type": "uint32_t"},
-                    {"name": "color attachments", "type": "render pass color attachment descriptor", "annotation": "const*", "length": "count"}
-                ]
-            },
-            {
-                "name": "set depth stencil attachment",
-                "args": [
-                    {"name": "depth stencil attachment", "type": "render pass depth stencil attachment descriptor", "annotation": "const*"}
-                ]
-            }
-        ],
-        "TODO": "Remove this builder and use render pass descriptor directly"
-    },
     "render pass descriptor": {
-        "category": "object"
+        "category": "structure",
+        "members": [
+            {"name": "color attachment count", "type": "uint32_t"},
+            {"name": "color attachments", "type": "render pass color attachment descriptor", "annotation": "const*const*", "length": "color attachment count"},
+            {"name": "depth stencil attachment", "type": "render pass depth stencil attachment descriptor", "annotation": "const*", "optional": true}
+        ]
     },
     "render pass encoder": {
         "category": "object",
diff --git a/examples/Animometer.cpp b/examples/Animometer.cpp
index e992643..020a512 100644
--- a/examples/Animometer.cpp
+++ b/examples/Animometer.cpp
@@ -131,18 +131,18 @@
 }
 
 void frame() {
-    dawn::Texture backbuffer;
-    dawn::RenderPassDescriptor renderPass;
-    GetNextRenderPassDescriptor(device, swapchain, depthStencilView, &backbuffer, &renderPass);
+    dawn::Texture backbuffer = swapchain.GetNextTexture();
 
     static int f = 0;
     f++;
 
     size_t i = 0;
 
+    utils::ComboRenderPassDescriptor renderPass({backbuffer.CreateDefaultTextureView()},
+                                                depthStencilView);
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(pipeline);
 
         for (int k = 0; k < 10000; k++) {
diff --git a/examples/CHelloTriangle.cpp b/examples/CHelloTriangle.cpp
index 4a9fe34..a3f4f82 100644
--- a/examples/CHelloTriangle.cpp
+++ b/examples/CHelloTriangle.cpp
@@ -118,23 +118,23 @@
         backbufferView = dawnTextureCreateDefaultTextureView(backbuffer);
     }
     dawnRenderPassDescriptor renderpassInfo;
+    dawnRenderPassColorAttachmentDescriptor colorAttachment;
+    dawnRenderPassColorAttachmentDescriptor* colorAttachments = {&colorAttachment};
     {
-        dawnRenderPassDescriptorBuilder builder = dawnDeviceCreateRenderPassDescriptorBuilder(device);
-        dawnRenderPassColorAttachmentDescriptor colorAttachment;
         colorAttachment.attachment = backbufferView;
         colorAttachment.resolveTarget = nullptr;
         colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
         colorAttachment.loadOp = DAWN_LOAD_OP_CLEAR;
         colorAttachment.storeOp = DAWN_STORE_OP_STORE;
-        dawnRenderPassDescriptorBuilderSetColorAttachments(builder, 1, &colorAttachment);
-        renderpassInfo = dawnRenderPassDescriptorBuilderGetResult(builder);
-        dawnRenderPassDescriptorBuilderRelease(builder);
+        renderpassInfo.colorAttachmentCount = 1;
+        renderpassInfo.colorAttachments = &colorAttachments;
+        renderpassInfo.depthStencilAttachment = nullptr;
     }
     dawnCommandBuffer commands;
     {
         dawnCommandEncoder encoder = dawnDeviceCreateCommandEncoder(device);
 
-        dawnRenderPassEncoder pass = dawnCommandEncoderBeginRenderPass(encoder, renderpassInfo);
+        dawnRenderPassEncoder pass = dawnCommandEncoderBeginRenderPass(encoder, &renderpassInfo);
         dawnRenderPassEncoderSetPipeline(pass, pipeline);
         dawnRenderPassEncoderDraw(pass, 3, 1, 0, 0);
         dawnRenderPassEncoderEndPass(pass);
@@ -147,7 +147,6 @@
     dawnQueueSubmit(queue, 1, &commands);
     dawnCommandBufferRelease(commands);
     dawnSwapChainPresent(swapchain, backbuffer);
-    dawnRenderPassDescriptorRelease(renderpassInfo);
     dawnTextureViewRelease(backbufferView);
 
     DoFlush();
diff --git a/examples/ComputeBoids.cpp b/examples/ComputeBoids.cpp
index d6d0e78..778d440 100644
--- a/examples/ComputeBoids.cpp
+++ b/examples/ComputeBoids.cpp
@@ -277,7 +277,7 @@
     }
 }
 
-dawn::CommandBuffer createCommandBuffer(const dawn::RenderPassDescriptor& renderPass, size_t i) {
+dawn::CommandBuffer createCommandBuffer(const dawn::Texture backbuffer, size_t i) {
     static const uint32_t zeroOffsets[1] = {0};
     auto& bufferDst = particleBuffers[(i + 1) % 2];
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
@@ -291,7 +291,9 @@
     }
 
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass);
+        utils::ComboRenderPassDescriptor renderPass({backbuffer.CreateDefaultTextureView()},
+                                                    depthStencilView);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(renderPipeline);
         pass.SetVertexBuffers(0, 1, &bufferDst, zeroOffsets);
         pass.SetVertexBuffers(1, 1, &modelBuffer, zeroOffsets);
@@ -316,11 +318,9 @@
 }
 
 void frame() {
-    dawn::Texture backbuffer;
-    dawn::RenderPassDescriptor renderPass;
-    GetNextRenderPassDescriptor(device, swapchain, depthStencilView, &backbuffer, &renderPass);
+    dawn::Texture backbuffer = swapchain.GetNextTexture();
 
-    dawn::CommandBuffer commandBuffer = createCommandBuffer(renderPass, pingpong);
+    dawn::CommandBuffer commandBuffer = createCommandBuffer(backbuffer, pingpong);
     queue.Submit(1, &commandBuffer);
     swapchain.Present(backbuffer);
     DoFlush();
diff --git a/examples/CppHelloTriangle.cpp b/examples/CppHelloTriangle.cpp
index 00e14ae..1c46f2e 100644
--- a/examples/CppHelloTriangle.cpp
+++ b/examples/CppHelloTriangle.cpp
@@ -160,14 +160,14 @@
     s.b += 0.02f;
     if (s.b >= 1.0f) {s.b = 0.0f;}
 
-    dawn::Texture backbuffer;
-    dawn::RenderPassDescriptor renderPass;
-    GetNextRenderPassDescriptor(device, swapchain, depthStencilView, &backbuffer, &renderPass);
+    dawn::Texture backbuffer = swapchain.GetNextTexture();
+    utils::ComboRenderPassDescriptor renderPass({backbuffer.CreateDefaultTextureView()},
+                                                depthStencilView);
 
     static const uint32_t vertexBufferOffsets[1] = {0};
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(pipeline);
         pass.SetBindGroup(0, bindGroup);
         pass.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets);
diff --git a/examples/CubeReflection.cpp b/examples/CubeReflection.cpp
index 728fbf0..93b5606 100644
--- a/examples/CubeReflection.cpp
+++ b/examples/CubeReflection.cpp
@@ -272,13 +272,13 @@
 
     cameraBuffer.SetSubData(0, sizeof(CameraData), reinterpret_cast<uint8_t*>(&cameraData));
 
-    dawn::Texture backbuffer;
-    dawn::RenderPassDescriptor renderPass;
-    GetNextRenderPassDescriptor(device, swapchain, depthStencilView, &backbuffer, &renderPass);
+    dawn::Texture backbuffer = swapchain.GetNextTexture();
+    utils::ComboRenderPassDescriptor renderPass({backbuffer.CreateDefaultTextureView()},
+                                                depthStencilView);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(pipeline);
         pass.SetBindGroup(0, bindGroup[0]);
         pass.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets);
diff --git a/examples/SampleUtils.cpp b/examples/SampleUtils.cpp
index b78cf58..b43d6e8 100644
--- a/examples/SampleUtils.cpp
+++ b/examples/SampleUtils.cpp
@@ -170,35 +170,6 @@
     return depthStencilTexture.CreateDefaultTextureView();
 }
 
-void GetNextRenderPassDescriptor(const dawn::Device& device,
-    const dawn::SwapChain& swapchain,
-    const dawn::TextureView& depthStencilView,
-    dawn::Texture* backbuffer,
-    dawn::RenderPassDescriptor* info) {
-    *backbuffer = swapchain.GetNextTexture();
-    auto backbufferView = backbuffer->CreateDefaultTextureView();
-    dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-    colorAttachment.attachment = backbufferView;
-    colorAttachment.resolveTarget = nullptr;
-    colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-    colorAttachment.loadOp = dawn::LoadOp::Clear;
-    colorAttachment.storeOp = dawn::StoreOp::Store;
-
-    dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
-    depthStencilAttachment.attachment = depthStencilView;
-    depthStencilAttachment.depthLoadOp = dawn::LoadOp::Clear;
-    depthStencilAttachment.stencilLoadOp = dawn::LoadOp::Clear;
-    depthStencilAttachment.clearDepth = 1.0f;
-    depthStencilAttachment.clearStencil = 0;
-    depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
-    depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
-
-    *info = device.CreateRenderPassDescriptorBuilder()
-        .SetColorAttachments(1, &colorAttachment)
-        .SetDepthStencilAttachment(&depthStencilAttachment)
-        .GetResult();
-}
-
 bool InitSample(int argc, const char** argv) {
     for (int i = 1; i < argc; i++) {
         if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) {
diff --git a/examples/SampleUtils.h b/examples/SampleUtils.h
index bbe37b2..3540109 100644
--- a/examples/SampleUtils.h
+++ b/examples/SampleUtils.h
@@ -27,8 +27,3 @@
 dawn::TextureFormat GetPreferredSwapChainTextureFormat();
 dawn::SwapChain GetSwapChain(const dawn::Device& device);
 dawn::TextureView CreateDefaultDepthStencilView(const dawn::Device& device);
-void GetNextRenderPassDescriptor(const dawn::Device& device,
-    const dawn::SwapChain& swapchain,
-    const dawn::TextureView& depthStencilView,
-    dawn::Texture* backbuffer,
-    dawn::RenderPassDescriptor* info);
diff --git a/examples/glTFViewer/glTFViewer.cpp b/examples/glTFViewer/glTFViewer.cpp
index 2097e86..329703d 100644
--- a/examples/glTFViewer/glTFViewer.cpp
+++ b/examples/glTFViewer/glTFViewer.cpp
@@ -600,14 +600,14 @@
     }
 
     void frame() {
-        dawn::Texture backbuffer;
-        dawn::RenderPassDescriptor renderPass;
-        GetNextRenderPassDescriptor(device, swapchain, depthStencilView, &backbuffer, &renderPass);
+        dawn::Texture backbuffer = swapchain.GetNextTexture();
 
         const auto& defaultSceneNodes = scene.scenes.at(scene.defaultScene);
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
         {
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass);
+            utils::ComboRenderPassDescriptor renderPass({backbuffer.CreateDefaultTextureView()},
+                                                        depthStencilView);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
             for (const auto& n : defaultSceneNodes) {
                 const auto& node = scene.nodes.at(n);
                 drawNode(pass, node);
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index 0b85bfe..7535d18 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -23,7 +23,6 @@
 #include "dawn_native/ComputePassEncoder.h"
 #include "dawn_native/Device.h"
 #include "dawn_native/ErrorData.h"
-#include "dawn_native/RenderPassDescriptor.h"
 #include "dawn_native/RenderPassEncoder.h"
 #include "dawn_native/RenderPipeline.h"
 
@@ -187,6 +186,117 @@
             return {};
         }
 
+        MaybeError ValidateAttachmentArrayLayersAndLevelCount(const TextureViewBase* attachment) {
+            // Currently we do not support layered rendering.
+            if (attachment->GetLayerCount() > 1) {
+                return DAWN_VALIDATION_ERROR(
+                    "The layer count of the texture view used as attachment cannot be greater than "
+                    "1");
+            }
+
+            if (attachment->GetLevelCount() > 1) {
+                return DAWN_VALIDATION_ERROR(
+                    "The mipmap level count of the texture view used as attachment cannot be "
+                    "greater than 1");
+            }
+
+            return {};
+        }
+
+        MaybeError ValidateOrSetAttachmentSize(const TextureViewBase* attachment,
+                                               uint32_t* width,
+                                               uint32_t* height) {
+            const Extent3D& textureSize = attachment->GetTexture()->GetSize();
+            const uint32_t attachmentWidth = textureSize.width >> attachment->GetBaseMipLevel();
+            const uint32_t attachmentHeight = textureSize.height >> attachment->GetBaseMipLevel();
+
+            if (*width == 0) {
+                DAWN_ASSERT(*height == 0);
+                *width = attachmentWidth;
+                *height = attachmentHeight;
+                DAWN_ASSERT(*width != 0 && *height != 0);
+            } else if (*width != attachmentWidth || *height != attachmentHeight) {
+                return DAWN_VALIDATION_ERROR("Attachment size mismatch");
+            }
+
+            return {};
+        }
+
+        MaybeError ValidateRenderPassColorAttachment(
+            const DeviceBase* device,
+            const RenderPassColorAttachmentDescriptor* colorAttachment,
+            uint32_t* width,
+            uint32_t* height) {
+            DAWN_ASSERT(colorAttachment != nullptr);
+
+            DAWN_TRY(device->ValidateObject(colorAttachment->attachment));
+
+            // TODO(jiawei.shao@intel.com): support resolve target for multisample color attachment.
+            if (colorAttachment->resolveTarget != nullptr) {
+                return DAWN_VALIDATION_ERROR("Resolve target is not supported now");
+            }
+
+            const TextureViewBase* attachment = colorAttachment->attachment;
+            if (!IsColorRenderableTextureFormat(attachment->GetFormat())) {
+                return DAWN_VALIDATION_ERROR(
+                    "The format of the texture view used as color attachment is not color "
+                    "renderable");
+            }
+
+            DAWN_TRY(ValidateAttachmentArrayLayersAndLevelCount(attachment));
+            DAWN_TRY(ValidateOrSetAttachmentSize(attachment, width, height));
+
+            return {};
+        }
+
+        MaybeError ValidateRenderPassDepthStencilAttachment(
+            const DeviceBase* device,
+            const RenderPassDepthStencilAttachmentDescriptor* depthStencilAttachment,
+            uint32_t* width,
+            uint32_t* height) {
+            DAWN_ASSERT(depthStencilAttachment != nullptr);
+
+            DAWN_TRY(device->ValidateObject(depthStencilAttachment->attachment));
+
+            const TextureViewBase* attachment = depthStencilAttachment->attachment;
+            if (!TextureFormatHasDepthOrStencil(attachment->GetFormat())) {
+                return DAWN_VALIDATION_ERROR(
+                    "The format of the texture view used as depth stencil attachment is not a "
+                    "depth stencil format");
+            }
+
+            DAWN_TRY(ValidateAttachmentArrayLayersAndLevelCount(attachment));
+            DAWN_TRY(ValidateOrSetAttachmentSize(attachment, width, height));
+
+            return {};
+        }
+
+        MaybeError ValidateRenderPassDescriptorAndSetSize(const DeviceBase* device,
+                                                          const RenderPassDescriptor* renderPass,
+                                                          uint32_t* width,
+                                                          uint32_t* height) {
+            if (renderPass->colorAttachmentCount > kMaxColorAttachments) {
+                return DAWN_VALIDATION_ERROR("Setting color attachments out of bounds");
+            }
+
+            for (uint32_t i = 0; i < renderPass->colorAttachmentCount; ++i) {
+                DAWN_TRY(ValidateRenderPassColorAttachment(device, renderPass->colorAttachments[i],
+                                                           width, height));
+            }
+
+            if (renderPass->depthStencilAttachment != nullptr) {
+                DAWN_TRY(ValidateRenderPassDepthStencilAttachment(
+                    device, renderPass->depthStencilAttachment, width, height));
+            }
+
+            if (renderPass->colorAttachmentCount == 0 &&
+                renderPass->depthStencilAttachment == nullptr) {
+                return DAWN_VALIDATION_ERROR("Cannot use render pass with no attachments.");
+            }
+
+            return {};
+        }
+
         enum class PassType {
             Render,
             Compute,
@@ -378,38 +488,53 @@
         return new ComputePassEncoderBase(GetDevice(), this, &mAllocator);
     }
 
-    RenderPassEncoderBase* CommandEncoderBase::BeginRenderPass(RenderPassDescriptorBase* info) {
+    RenderPassEncoderBase* CommandEncoderBase::BeginRenderPass(const RenderPassDescriptor* info) {
+        DeviceBase* device = GetDevice();
+
         if (ConsumedError(ValidateCanRecordTopLevelCommands())) {
-            return nullptr;
+            // Using nullptr as allocator will make ValidateCanRecordCommands() always return false,
+            // thus any API call on the return value will result in a Dawn validation error.
+            return new RenderPassEncoderBase(device, this, nullptr);
         }
 
-        if (info == nullptr) {
-            HandleError("RenderPassDescriptor cannot be null");
-            return nullptr;
+        uint32_t width = 0;
+        uint32_t height = 0;
+        if (ConsumedError(ValidateRenderPassDescriptorAndSetSize(device, info, &width, &height))) {
+            return new RenderPassEncoderBase(device, this, nullptr);
         }
 
+        mEncodingState = EncodingState::RenderPass;
+
         BeginRenderPassCmd* cmd = mAllocator.Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
         new (cmd) BeginRenderPassCmd;
 
-        for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
-            const RenderPassColorAttachmentInfo& colorAttachment = info->GetColorAttachment(i);
-            if (colorAttachment.view.Get() != nullptr) {
+        for (uint32_t i = 0; i < info->colorAttachmentCount; ++i) {
+            if (info->colorAttachments[i] != nullptr) {
                 cmd->colorAttachmentsSet.set(i);
-                cmd->colorAttachments[i] = colorAttachment;
+                cmd->colorAttachments[i].view = info->colorAttachments[i]->attachment;
+                cmd->colorAttachments[i].resolveTarget = info->colorAttachments[i]->resolveTarget;
+                cmd->colorAttachments[i].loadOp = info->colorAttachments[i]->loadOp;
+                cmd->colorAttachments[i].storeOp = info->colorAttachments[i]->storeOp;
+                cmd->colorAttachments[i].clearColor = info->colorAttachments[i]->clearColor;
             }
         }
 
-        cmd->hasDepthStencilAttachment = info->HasDepthStencilAttachment();
+        cmd->hasDepthStencilAttachment = info->depthStencilAttachment != nullptr;
         if (cmd->hasDepthStencilAttachment) {
-            const RenderPassDepthStencilAttachmentInfo& depthStencilAttachment =
-                info->GetDepthStencilAttachment();
-            cmd->depthStencilAttachment = depthStencilAttachment;
+            cmd->hasDepthStencilAttachment = true;
+            cmd->depthStencilAttachment.view = info->depthStencilAttachment->attachment;
+            cmd->depthStencilAttachment.clearDepth = info->depthStencilAttachment->clearDepth;
+            cmd->depthStencilAttachment.clearStencil = info->depthStencilAttachment->clearStencil;
+            cmd->depthStencilAttachment.depthLoadOp = info->depthStencilAttachment->depthLoadOp;
+            cmd->depthStencilAttachment.depthStoreOp = info->depthStencilAttachment->depthStoreOp;
+            cmd->depthStencilAttachment.stencilLoadOp = info->depthStencilAttachment->stencilLoadOp;
+            cmd->depthStencilAttachment.stencilStoreOp =
+                info->depthStencilAttachment->stencilStoreOp;
         }
 
-        cmd->width = info->GetWidth();
-        cmd->height = info->GetHeight();
+        cmd->width = width;
+        cmd->height = height;
 
-        mEncodingState = EncodingState::RenderPass;
         return new RenderPassEncoderBase(GetDevice(), this, &mAllocator);
     }
 
diff --git a/src/dawn_native/CommandEncoder.h b/src/dawn_native/CommandEncoder.h
index 6935847..20d8901 100644
--- a/src/dawn_native/CommandEncoder.h
+++ b/src/dawn_native/CommandEncoder.h
@@ -42,7 +42,7 @@
 
         // Dawn API
         ComputePassEncoderBase* BeginComputePass();
-        RenderPassEncoderBase* BeginRenderPass(RenderPassDescriptorBase* info);
+        RenderPassEncoderBase* BeginRenderPass(const RenderPassDescriptor* info);
         void CopyBufferToBuffer(BufferBase* source,
                                 uint32_t sourceOffset,
                                 BufferBase* destination,
diff --git a/src/dawn_native/Commands.h b/src/dawn_native/Commands.h
index 94e19c5..92913c0 100644
--- a/src/dawn_native/Commands.h
+++ b/src/dawn_native/Commands.h
@@ -62,7 +62,7 @@
         Ref<TextureViewBase> resolveTarget;
         dawn::LoadOp loadOp;
         dawn::StoreOp storeOp;
-        std::array<float, 4> clearColor = {{0.0f, 0.0f, 0.0f, 0.0f}};
+        dawn_native::Color clearColor;
     };
 
     struct RenderPassDepthStencilAttachmentInfo {
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 174b722..5d888b1 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -28,7 +28,6 @@
 #include "dawn_native/InputState.h"
 #include "dawn_native/PipelineLayout.h"
 #include "dawn_native/Queue.h"
-#include "dawn_native/RenderPassDescriptor.h"
 #include "dawn_native/RenderPipeline.h"
 #include "dawn_native/Sampler.h"
 #include "dawn_native/ShaderModule.h"
@@ -194,9 +193,6 @@
 
         return result;
     }
-    RenderPassDescriptorBuilder* DeviceBase::CreateRenderPassDescriptorBuilder() {
-        return new RenderPassDescriptorBuilder(this);
-    }
     SamplerBase* DeviceBase::CreateSampler(const SamplerDescriptor* descriptor) {
         SamplerBase* result = nullptr;
 
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index 0eb9810..97e002e 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -61,8 +61,6 @@
 
         virtual CommandBufferBase* CreateCommandBuffer(CommandEncoderBase* encoder) = 0;
         virtual InputStateBase* CreateInputState(InputStateBuilder* builder) = 0;
-        virtual RenderPassDescriptorBase* CreateRenderPassDescriptor(
-            RenderPassDescriptorBuilder* builder) = 0;
 
         virtual Serial GetCompletedCommandSerial() const = 0;
         virtual Serial GetLastSubmittedCommandSerial() const = 0;
@@ -97,7 +95,6 @@
         InputStateBuilder* CreateInputStateBuilder();
         PipelineLayoutBase* CreatePipelineLayout(const PipelineLayoutDescriptor* descriptor);
         QueueBase* CreateQueue();
-        RenderPassDescriptorBuilder* CreateRenderPassDescriptorBuilder();
         RenderPipelineBase* CreateRenderPipeline(const RenderPipelineDescriptor* descriptor);
         SamplerBase* CreateSampler(const SamplerDescriptor* descriptor);
         ShaderModuleBase* CreateShaderModule(const ShaderModuleDescriptor* descriptor);
diff --git a/src/dawn_native/Forward.h b/src/dawn_native/Forward.h
index 2d1af63..c11dc24 100644
--- a/src/dawn_native/Forward.h
+++ b/src/dawn_native/Forward.h
@@ -34,8 +34,6 @@
     class PipelineBase;
     class PipelineLayoutBase;
     class QueueBase;
-    class RenderPassDescriptorBase;
-    class RenderPassDescriptorBuilder;
     class RenderPassEncoderBase;
     class RenderPipelineBase;
     class SamplerBase;
diff --git a/src/dawn_native/ProgrammablePassEncoder.cpp b/src/dawn_native/ProgrammablePassEncoder.cpp
index 0962ba5..7a16f31 100644
--- a/src/dawn_native/ProgrammablePassEncoder.cpp
+++ b/src/dawn_native/ProgrammablePassEncoder.cpp
@@ -106,7 +106,7 @@
 
     MaybeError ProgrammablePassEncoder::ValidateCanRecordCommands() const {
         if (mAllocator == nullptr) {
-            return DAWN_VALIDATION_ERROR("Recording in an already ended pass encoder");
+            return DAWN_VALIDATION_ERROR("Recording in an error or already ended pass encoder");
         }
 
         return nullptr;
diff --git a/src/dawn_native/RenderPassDescriptor.cpp b/src/dawn_native/RenderPassDescriptor.cpp
deleted file mode 100644
index 99730ba..0000000
--- a/src/dawn_native/RenderPassDescriptor.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "dawn_native/RenderPassDescriptor.h"
-
-#include "common/Assert.h"
-#include "common/BitSetIterator.h"
-#include "dawn_native/Device.h"
-#include "dawn_native/Texture.h"
-
-namespace dawn_native {
-
-    // RenderPassDescriptor
-
-    RenderPassDescriptorBase::RenderPassDescriptorBase(RenderPassDescriptorBuilder* builder)
-        : ObjectBase(builder->GetDevice()),
-          mColorAttachmentsSet(builder->mColorAttachmentsSet),
-          mColorAttachments(builder->mColorAttachments),
-          mDepthStencilAttachmentSet(builder->mDepthStencilAttachmentSet),
-          mDepthStencilAttachment(builder->mDepthStencilAttachment),
-          mWidth(builder->mWidth),
-          mHeight(builder->mHeight) {
-    }
-
-    std::bitset<kMaxColorAttachments> RenderPassDescriptorBase::GetColorAttachmentMask() const {
-        return mColorAttachmentsSet;
-    }
-
-    bool RenderPassDescriptorBase::HasDepthStencilAttachment() const {
-        return mDepthStencilAttachmentSet;
-    }
-
-    const RenderPassColorAttachmentInfo& RenderPassDescriptorBase::GetColorAttachment(
-        uint32_t attachment) const {
-        ASSERT(attachment < kMaxColorAttachments);
-        ASSERT(mColorAttachmentsSet[attachment]);
-
-        return mColorAttachments[attachment];
-    }
-
-    RenderPassColorAttachmentInfo& RenderPassDescriptorBase::GetColorAttachment(
-        uint32_t attachment) {
-        ASSERT(attachment < kMaxColorAttachments);
-        ASSERT(mColorAttachmentsSet[attachment]);
-
-        return mColorAttachments[attachment];
-    }
-
-    const RenderPassDepthStencilAttachmentInfo&
-    RenderPassDescriptorBase::GetDepthStencilAttachment() const {
-        ASSERT(mDepthStencilAttachmentSet);
-
-        return mDepthStencilAttachment;
-    }
-
-    RenderPassDepthStencilAttachmentInfo& RenderPassDescriptorBase::GetDepthStencilAttachment() {
-        ASSERT(mDepthStencilAttachmentSet);
-
-        return mDepthStencilAttachment;
-    }
-
-    uint32_t RenderPassDescriptorBase::GetWidth() const {
-        return mWidth;
-    }
-
-    uint32_t RenderPassDescriptorBase::GetHeight() const {
-        return mHeight;
-    }
-
-    // RenderPassDescriptorBuilder
-
-    RenderPassDescriptorBuilder::RenderPassDescriptorBuilder(DeviceBase* device) : Builder(device) {
-    }
-
-    bool RenderPassDescriptorBuilder::CheckArrayLayersAndLevelCountForAttachment(
-        const TextureViewBase* textureView) {
-        // Currently we do not support layered rendering.
-        if (textureView->GetLayerCount() > 1) {
-            HandleError(
-                "The layer count of the texture view used as attachment cannot be greater than 1");
-            return false;
-        }
-
-        if (textureView->GetLevelCount() > 1) {
-            HandleError(
-                "The mipmap level count of the texture view used as attachment cannot be greater "
-                "than 1");
-            return false;
-        }
-        return true;
-    }
-
-    RenderPassDescriptorBase* RenderPassDescriptorBuilder::GetResultImpl() {
-        auto CheckOrSetSize = [this](const TextureViewBase* attachment) -> bool {
-            uint32_t mipLevel = attachment->GetBaseMipLevel();
-            if (this->mWidth == 0) {
-                ASSERT(this->mHeight == 0);
-
-                this->mWidth = attachment->GetTexture()->GetSize().width >> mipLevel;
-                this->mHeight = attachment->GetTexture()->GetSize().height >> mipLevel;
-                ASSERT(this->mWidth != 0 && this->mHeight != 0);
-
-                return true;
-            }
-
-            ASSERT(this->mWidth != 0 && this->mHeight != 0);
-            return this->mWidth == attachment->GetTexture()->GetSize().width >> mipLevel &&
-                   this->mHeight == attachment->GetTexture()->GetSize().height >> mipLevel;
-        };
-
-        uint32_t attachmentCount = 0;
-        for (uint32_t i : IterateBitSet(mColorAttachmentsSet)) {
-            attachmentCount++;
-            if (!CheckOrSetSize(mColorAttachments[i].view.Get())) {
-                HandleError("Attachment size mismatch");
-                return nullptr;
-            }
-        }
-
-        if (mDepthStencilAttachmentSet) {
-            attachmentCount++;
-            if (!CheckOrSetSize(mDepthStencilAttachment.view.Get())) {
-                HandleError("Attachment size mismatch");
-                return nullptr;
-            }
-        }
-
-        if (attachmentCount == 0) {
-            HandleError("Should have at least one attachment");
-            return nullptr;
-        }
-
-        return GetDevice()->CreateRenderPassDescriptor(this);
-    }
-
-    void RenderPassDescriptorBuilder::SetColorAttachments(
-        uint32_t count,
-        const RenderPassColorAttachmentDescriptor* attachments) {
-        if (count > kMaxColorAttachments) {
-            HandleError("Setting color attachments out of bounds");
-            return;
-        }
-
-        for (uint32_t i = 0; i < count; ++i) {
-            // TODO(jiawei.shao@intel.com): support resolve target for multisample color attachment.
-            if (attachments[i].resolveTarget != nullptr) {
-                HandleError("Resolve target is not supported now");
-                return;
-            }
-
-            TextureViewBase* textureView = attachments[i].attachment;
-            if (textureView == nullptr) {
-                continue;
-            }
-
-            // TODO(cwallez@chromium.org): Once RenderPassDescriptor doesn't use a builder, check
-            // that the textureView is a valid object.
-            // See https://bugs.chromium.org/p/dawn/issues/detail?id=6
-
-            if (!IsColorRenderableTextureFormat(textureView->GetFormat())) {
-                HandleError(
-                    "The format of the texture view used as color attachment is not color "
-                    "renderable");
-                return;
-            }
-
-            if (!CheckArrayLayersAndLevelCountForAttachment(textureView)) {
-                return;
-            }
-
-            // TODO(jiawei.shao@intel.com): set and make use of storeOp
-            mColorAttachmentsSet.set(i);
-            mColorAttachments[i].loadOp = attachments[i].loadOp;
-            mColorAttachments[i].view = textureView;
-
-            mColorAttachments[i].clearColor[0] = attachments[i].clearColor.r;
-            mColorAttachments[i].clearColor[1] = attachments[i].clearColor.g;
-            mColorAttachments[i].clearColor[2] = attachments[i].clearColor.b;
-            mColorAttachments[i].clearColor[3] = attachments[i].clearColor.a;
-        }
-    }
-
-    void RenderPassDescriptorBuilder::SetDepthStencilAttachment(
-        const RenderPassDepthStencilAttachmentDescriptor* attachment) {
-        TextureViewBase* textureView = attachment->attachment;
-
-        // TODO(cwallez@chromium.org): Once RenderPassDescriptor doesn't use a builder, check that
-        // the textureView is a valid object.
-        // See https://bugs.chromium.org/p/dawn/issues/detail?id=6
-        if (textureView == nullptr) {
-            HandleError("Texture view cannot be nullptr");
-            return;
-        }
-
-        if (!TextureFormatHasDepthOrStencil(textureView->GetFormat())) {
-            HandleError(
-                "The format of the texture view used as depth stencil attachment is not a depth "
-                "stencil format");
-            return;
-        }
-
-        if (!CheckArrayLayersAndLevelCountForAttachment(textureView)) {
-            return;
-        }
-
-        // TODO(jiawei.shao@intel.com): set and make use of depthStoreOp and stencilStoreOp
-        mDepthStencilAttachmentSet = true;
-        mDepthStencilAttachment.depthLoadOp = attachment->depthLoadOp;
-        mDepthStencilAttachment.stencilLoadOp = attachment->stencilLoadOp;
-        mDepthStencilAttachment.view = textureView;
-        mDepthStencilAttachment.clearDepth = attachment->clearDepth;
-        mDepthStencilAttachment.clearStencil = attachment->clearStencil;
-    }
-
-}  // namespace dawn_native
diff --git a/src/dawn_native/RenderPassDescriptor.h b/src/dawn_native/RenderPassDescriptor.h
deleted file mode 100644
index 1d9e145..0000000
--- a/src/dawn_native/RenderPassDescriptor.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef DAWNNATIVE_RENDERPASSDESCRIPTOR_H_
-#define DAWNNATIVE_RENDERPASSDESCRIPTOR_H_
-
-#include "common/Constants.h"
-#include "dawn_native/Builder.h"
-#include "dawn_native/Commands.h"
-#include "dawn_native/Forward.h"
-#include "dawn_native/ObjectBase.h"
-
-#include "dawn_native/dawn_platform.h"
-
-#include <array>
-#include <bitset>
-#include <vector>
-
-namespace dawn_native {
-
-    // RenderPassDescriptor contains the list of attachments for a renderpass along with data such
-    // as the load operation and the clear values for the attachments.
-
-    class RenderPassDescriptorBase : public ObjectBase {
-      public:
-        RenderPassDescriptorBase(RenderPassDescriptorBuilder* builder);
-
-        std::bitset<kMaxColorAttachments> GetColorAttachmentMask() const;
-        bool HasDepthStencilAttachment() const;
-
-        const RenderPassColorAttachmentInfo& GetColorAttachment(uint32_t attachment) const;
-        RenderPassColorAttachmentInfo& GetColorAttachment(uint32_t attachment);
-        const RenderPassDepthStencilAttachmentInfo& GetDepthStencilAttachment() const;
-        RenderPassDepthStencilAttachmentInfo& GetDepthStencilAttachment();
-
-        // All attachments of the render pass have the same size, these return that size.
-        uint32_t GetWidth() const;
-        uint32_t GetHeight() const;
-
-      private:
-        std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
-        std::array<RenderPassColorAttachmentInfo, kMaxColorAttachments> mColorAttachments;
-
-        bool mDepthStencilAttachmentSet;
-        RenderPassDepthStencilAttachmentInfo mDepthStencilAttachment;
-
-        uint32_t mWidth;
-        uint32_t mHeight;
-    };
-
-    // TODO(jiawei.shao@intel.com): remove RenderPassDescriptorBuilder and set data into
-    // RenderPassDescriptor directly.
-    class RenderPassDescriptorBuilder : public Builder<RenderPassDescriptorBase> {
-      public:
-        RenderPassDescriptorBuilder(DeviceBase* device);
-
-        // Dawn API
-        RenderPassDescriptorBase* GetResultImpl() override;
-        void SetColorAttachments(uint32_t count,
-                                 const RenderPassColorAttachmentDescriptor* attachments);
-        void SetDepthStencilAttachment(
-            const RenderPassDepthStencilAttachmentDescriptor* attachment);
-
-      private:
-        friend class RenderPassDescriptorBase;
-
-        bool CheckArrayLayersAndLevelCountForAttachment(const TextureViewBase* textureView);
-
-        std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
-        std::array<RenderPassColorAttachmentInfo, kMaxColorAttachments> mColorAttachments;
-
-        bool mDepthStencilAttachmentSet = false;
-        RenderPassDepthStencilAttachmentInfo mDepthStencilAttachment;
-
-        uint32_t mWidth = 0;
-        uint32_t mHeight = 0;
-    };
-
-}  // namespace dawn_native
-
-#endif  // DAWNNATIVE_RENDERPASS_H_
diff --git a/src/dawn_native/RenderPipeline.cpp b/src/dawn_native/RenderPipeline.cpp
index cebe557..12531dc 100644
--- a/src/dawn_native/RenderPipeline.cpp
+++ b/src/dawn_native/RenderPipeline.cpp
@@ -18,7 +18,6 @@
 #include "dawn_native/Commands.h"
 #include "dawn_native/Device.h"
 #include "dawn_native/InputState.h"
-#include "dawn_native/RenderPassDescriptor.h"
 #include "dawn_native/Texture.h"
 #include "dawn_native/ValidationUtils_autogen.h"
 
diff --git a/src/dawn_native/ToBackend.h b/src/dawn_native/ToBackend.h
index 1ad86a8..1e09b1c 100644
--- a/src/dawn_native/ToBackend.h
+++ b/src/dawn_native/ToBackend.h
@@ -74,11 +74,6 @@
     };
 
     template <typename BackendTraits>
-    struct ToBackendTraits<RenderPassDescriptorBase, BackendTraits> {
-        using BackendType = typename BackendTraits::RenderPassDescriptorType;
-    };
-
-    template <typename BackendTraits>
     struct ToBackendTraits<RenderPipelineBase, BackendTraits> {
         using BackendType = typename BackendTraits::RenderPipelineType;
     };
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 30bb086..7d59f7d 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -609,7 +609,7 @@
                 // Load op - color
                 if (attachmentInfo.loadOp == dawn::LoadOp::Clear) {
                     D3D12_CPU_DESCRIPTOR_HANDLE handle = args.RTVs[i];
-                    commandList->ClearRenderTargetView(handle, attachmentInfo.clearColor.data(), 0,
+                    commandList->ClearRenderTargetView(handle, &attachmentInfo.clearColor.r, 0,
                                                        nullptr);
                 }
             }
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index 5297f3f..6366e81 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -17,7 +17,6 @@
 #include "common/Assert.h"
 #include "dawn_native/BackendConnection.h"
 #include "dawn_native/DynamicUploader.h"
-#include "dawn_native/RenderPassDescriptor.h"
 #include "dawn_native/d3d12/AdapterD3D12.h"
 #include "dawn_native/d3d12/BackendD3D12.h"
 #include "dawn_native/d3d12/BindGroupD3D12.h"
@@ -227,10 +226,6 @@
     ResultOrError<QueueBase*> Device::CreateQueueImpl() {
         return new Queue(this);
     }
-    RenderPassDescriptorBase* Device::CreateRenderPassDescriptor(
-        RenderPassDescriptorBuilder* builder) {
-        return new RenderPassDescriptor(builder);
-    }
     ResultOrError<RenderPipelineBase*> Device::CreateRenderPipelineImpl(
         const RenderPipelineDescriptor* descriptor) {
         return new RenderPipeline(this, descriptor);
diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h
index ef1950c..98118ea 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.h
+++ b/src/dawn_native/d3d12/DeviceD3D12.h
@@ -42,8 +42,6 @@
 
         CommandBufferBase* CreateCommandBuffer(CommandEncoderBase* encoder) override;
         InputStateBase* CreateInputState(InputStateBuilder* builder) override;
-        RenderPassDescriptorBase* CreateRenderPassDescriptor(
-            RenderPassDescriptorBuilder* builder) override;
 
         Serial GetCompletedCommandSerial() const final override;
         Serial GetLastSubmittedCommandSerial() const final override;
diff --git a/src/dawn_native/d3d12/Forward.h b/src/dawn_native/d3d12/Forward.h
index ed415f6..e93b611 100644
--- a/src/dawn_native/d3d12/Forward.h
+++ b/src/dawn_native/d3d12/Forward.h
@@ -29,7 +29,6 @@
     class InputState;
     class PipelineLayout;
     class Queue;
-    using RenderPassDescriptor = RenderPassDescriptorBase;
     class RenderPipeline;
     class Sampler;
     class ShaderModule;
@@ -49,7 +48,6 @@
         using InputStateType = InputState;
         using PipelineLayoutType = PipelineLayout;
         using QueueType = Queue;
-        using RenderPassDescriptorType = RenderPassDescriptor;
         using RenderPipelineType = RenderPipeline;
         using SamplerType = Sampler;
         using ShaderModuleType = ShaderModule;
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index 43090ef..064f6eb 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -56,9 +56,9 @@
 
                 if (attachmentInfo.loadOp == dawn::LoadOp::Clear) {
                     descriptor.colorAttachments[i].loadAction = MTLLoadActionClear;
-                    descriptor.colorAttachments[i].clearColor = MTLClearColorMake(
-                        attachmentInfo.clearColor[0], attachmentInfo.clearColor[1],
-                        attachmentInfo.clearColor[2], attachmentInfo.clearColor[3]);
+                    descriptor.colorAttachments[i].clearColor =
+                        MTLClearColorMake(attachmentInfo.clearColor.r, attachmentInfo.clearColor.g,
+                                          attachmentInfo.clearColor.b, attachmentInfo.clearColor.a);
                 } else {
                     descriptor.colorAttachments[i].loadAction = MTLLoadActionLoad;
                 }
diff --git a/src/dawn_native/metal/DeviceMTL.h b/src/dawn_native/metal/DeviceMTL.h
index 5d1e1df..6969b5d 100644
--- a/src/dawn_native/metal/DeviceMTL.h
+++ b/src/dawn_native/metal/DeviceMTL.h
@@ -38,8 +38,6 @@
 
         CommandBufferBase* CreateCommandBuffer(CommandEncoderBase* encoder) override;
         InputStateBase* CreateInputState(InputStateBuilder* builder) override;
-        RenderPassDescriptorBase* CreateRenderPassDescriptor(
-            RenderPassDescriptorBuilder* builder) override;
 
         Serial GetCompletedCommandSerial() const final override;
         Serial GetLastSubmittedCommandSerial() const final override;
diff --git a/src/dawn_native/metal/DeviceMTL.mm b/src/dawn_native/metal/DeviceMTL.mm
index 0a07d75..3037e6f 100644
--- a/src/dawn_native/metal/DeviceMTL.mm
+++ b/src/dawn_native/metal/DeviceMTL.mm
@@ -18,7 +18,6 @@
 #include "dawn_native/BindGroup.h"
 #include "dawn_native/BindGroupLayout.h"
 #include "dawn_native/DynamicUploader.h"
-#include "dawn_native/RenderPassDescriptor.h"
 #include "dawn_native/metal/BufferMTL.h"
 #include "dawn_native/metal/CommandBufferMTL.h"
 #include "dawn_native/metal/ComputePipelineMTL.h"
@@ -91,10 +90,6 @@
         const PipelineLayoutDescriptor* descriptor) {
         return new PipelineLayout(this, descriptor);
     }
-    RenderPassDescriptorBase* Device::CreateRenderPassDescriptor(
-        RenderPassDescriptorBuilder* builder) {
-        return new RenderPassDescriptor(builder);
-    }
     ResultOrError<QueueBase*> Device::CreateQueueImpl() {
         return new Queue(this);
     }
diff --git a/src/dawn_native/metal/Forward.h b/src/dawn_native/metal/Forward.h
index fb9c4c8..f2a2e3c 100644
--- a/src/dawn_native/metal/Forward.h
+++ b/src/dawn_native/metal/Forward.h
@@ -20,7 +20,6 @@
 namespace {
     class BindGroupBase;
     class BindGroup;
-    class RenderPassDescriptor;
 }  // namespace
 
 namespace dawn_native { namespace metal {
@@ -36,7 +35,6 @@
     class InputState;
     class PipelineLayout;
     class Queue;
-    using RenderPassDescriptor = RenderPassDescriptorBase;
     class RenderPipeline;
     class Sampler;
     class ShaderModule;
@@ -56,7 +54,6 @@
         using InputStateType = InputState;
         using PipelineLayoutType = PipelineLayout;
         using QueueType = Queue;
-        using RenderPassDescriptorType = RenderPassDescriptor;
         using RenderPipelineType = RenderPipeline;
         using SamplerType = Sampler;
         using ShaderModuleType = ShaderModule;
diff --git a/src/dawn_native/null/DeviceNull.cpp b/src/dawn_native/null/DeviceNull.cpp
index 50b5216..f2832d0 100644
--- a/src/dawn_native/null/DeviceNull.cpp
+++ b/src/dawn_native/null/DeviceNull.cpp
@@ -92,10 +92,6 @@
     ResultOrError<QueueBase*> Device::CreateQueueImpl() {
         return new Queue(this);
     }
-    RenderPassDescriptorBase* Device::CreateRenderPassDescriptor(
-        RenderPassDescriptorBuilder* builder) {
-        return new RenderPassDescriptor(builder);
-    }
     ResultOrError<RenderPipelineBase*> Device::CreateRenderPipelineImpl(
         const RenderPipelineDescriptor* descriptor) {
         return new RenderPipeline(this, descriptor);
diff --git a/src/dawn_native/null/DeviceNull.h b/src/dawn_native/null/DeviceNull.h
index 5686890..0b5d40f 100644
--- a/src/dawn_native/null/DeviceNull.h
+++ b/src/dawn_native/null/DeviceNull.h
@@ -25,7 +25,6 @@
 #include "dawn_native/InputState.h"
 #include "dawn_native/PipelineLayout.h"
 #include "dawn_native/Queue.h"
-#include "dawn_native/RenderPassDescriptor.h"
 #include "dawn_native/RenderPipeline.h"
 #include "dawn_native/RingBuffer.h"
 #include "dawn_native/Sampler.h"
@@ -48,7 +47,6 @@
     using InputState = InputStateBase;
     using PipelineLayout = PipelineLayoutBase;
     class Queue;
-    using RenderPassDescriptor = RenderPassDescriptorBase;
     using RenderPipeline = RenderPipelineBase;
     using Sampler = SamplerBase;
     using ShaderModule = ShaderModuleBase;
@@ -67,7 +65,6 @@
         using InputStateType = InputState;
         using PipelineLayoutType = PipelineLayout;
         using QueueType = Queue;
-        using RenderPassDescriptorType = RenderPassDescriptor;
         using RenderPipelineType = RenderPipeline;
         using SamplerType = Sampler;
         using ShaderModuleType = ShaderModule;
@@ -93,8 +90,6 @@
 
         CommandBufferBase* CreateCommandBuffer(CommandEncoderBase* encoder) override;
         InputStateBase* CreateInputState(InputStateBuilder* builder) override;
-        RenderPassDescriptorBase* CreateRenderPassDescriptor(
-            RenderPassDescriptorBuilder* builder) override;
 
         Serial GetCompletedCommandSerial() const final override;
         Serial GetLastSubmittedCommandSerial() const final override;
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index 7acecc7..ea66e2c 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -546,7 +546,7 @@
 
                 // Load op - color
                 if (attachmentInfo.loadOp == dawn::LoadOp::Clear) {
-                    glClearBufferfv(GL_COLOR, i, attachmentInfo.clearColor.data());
+                    glClearBufferfv(GL_COLOR, i, &attachmentInfo.clearColor.r);
                 }
             }
 
diff --git a/src/dawn_native/opengl/DeviceGL.cpp b/src/dawn_native/opengl/DeviceGL.cpp
index 34d2737..f2a3edf 100644
--- a/src/dawn_native/opengl/DeviceGL.cpp
+++ b/src/dawn_native/opengl/DeviceGL.cpp
@@ -18,7 +18,6 @@
 #include "dawn_native/BindGroup.h"
 #include "dawn_native/BindGroupLayout.h"
 #include "dawn_native/DynamicUploader.h"
-#include "dawn_native/RenderPassDescriptor.h"
 #include "dawn_native/opengl/BufferGL.h"
 #include "dawn_native/opengl/CommandBufferGL.h"
 #include "dawn_native/opengl/ComputePipelineGL.h"
@@ -78,10 +77,6 @@
     ResultOrError<QueueBase*> Device::CreateQueueImpl() {
         return new Queue(this);
     }
-    RenderPassDescriptorBase* Device::CreateRenderPassDescriptor(
-        RenderPassDescriptorBuilder* builder) {
-        return new RenderPassDescriptor(builder);
-    }
     ResultOrError<RenderPipelineBase*> Device::CreateRenderPipelineImpl(
         const RenderPipelineDescriptor* descriptor) {
         return new RenderPipeline(this, descriptor);
diff --git a/src/dawn_native/opengl/DeviceGL.h b/src/dawn_native/opengl/DeviceGL.h
index e66981e..43fdf65 100644
--- a/src/dawn_native/opengl/DeviceGL.h
+++ b/src/dawn_native/opengl/DeviceGL.h
@@ -42,8 +42,6 @@
         // Dawn API
         CommandBufferBase* CreateCommandBuffer(CommandEncoderBase* encoder) override;
         InputStateBase* CreateInputState(InputStateBuilder* builder) override;
-        RenderPassDescriptorBase* CreateRenderPassDescriptor(
-            RenderPassDescriptorBuilder* builder) override;
 
         Serial GetCompletedCommandSerial() const final override;
         Serial GetLastSubmittedCommandSerial() const final override;
diff --git a/src/dawn_native/opengl/Forward.h b/src/dawn_native/opengl/Forward.h
index 486bb13..d4bfac6 100644
--- a/src/dawn_native/opengl/Forward.h
+++ b/src/dawn_native/opengl/Forward.h
@@ -36,7 +36,6 @@
     class PersistentPipelineState;
     class PipelineLayout;
     class Queue;
-    using RenderPassDescriptor = RenderPassDescriptorBase;
     class RenderPipeline;
     class Sampler;
     class ShaderModule;
@@ -55,7 +54,6 @@
         using InputStateType = InputState;
         using PipelineLayoutType = PipelineLayout;
         using QueueType = Queue;
-        using RenderPassDescriptorType = RenderPassDescriptor;
         using RenderPipelineType = RenderPipeline;
         using SamplerType = Sampler;
         using ShaderModuleType = ShaderModule;
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 92cc724..3e8d794 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -148,10 +148,10 @@
 
                     attachments[attachmentCount] = view->GetHandle();
 
-                    clearValues[attachmentCount].color.float32[0] = attachmentInfo.clearColor[0];
-                    clearValues[attachmentCount].color.float32[1] = attachmentInfo.clearColor[1];
-                    clearValues[attachmentCount].color.float32[2] = attachmentInfo.clearColor[2];
-                    clearValues[attachmentCount].color.float32[3] = attachmentInfo.clearColor[3];
+                    clearValues[attachmentCount].color.float32[0] = attachmentInfo.clearColor.r;
+                    clearValues[attachmentCount].color.float32[1] = attachmentInfo.clearColor.g;
+                    clearValues[attachmentCount].color.float32[2] = attachmentInfo.clearColor.b;
+                    clearValues[attachmentCount].color.float32[3] = attachmentInfo.clearColor.a;
 
                     attachmentCount++;
                 }
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index c6dae49..aad6e2f 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -19,7 +19,6 @@
 #include "dawn_native/Commands.h"
 #include "dawn_native/DynamicUploader.h"
 #include "dawn_native/ErrorData.h"
-#include "dawn_native/RenderPassDescriptor.h"
 #include "dawn_native/vulkan/AdapterVk.h"
 #include "dawn_native/vulkan/BackendVk.h"
 #include "dawn_native/vulkan/BindGroupLayoutVk.h"
@@ -163,10 +162,6 @@
     ResultOrError<QueueBase*> Device::CreateQueueImpl() {
         return new Queue(this);
     }
-    RenderPassDescriptorBase* Device::CreateRenderPassDescriptor(
-        RenderPassDescriptorBuilder* builder) {
-        return new RenderPassDescriptor(builder);
-    }
     ResultOrError<RenderPipelineBase*> Device::CreateRenderPipelineImpl(
         const RenderPipelineDescriptor* descriptor) {
         return new RenderPipeline(this, descriptor);
diff --git a/src/dawn_native/vulkan/DeviceVk.h b/src/dawn_native/vulkan/DeviceVk.h
index 86653c2..95cdc54 100644
--- a/src/dawn_native/vulkan/DeviceVk.h
+++ b/src/dawn_native/vulkan/DeviceVk.h
@@ -66,8 +66,6 @@
         // Dawn API
         CommandBufferBase* CreateCommandBuffer(CommandEncoderBase* encoder) override;
         InputStateBase* CreateInputState(InputStateBuilder* builder) override;
-        RenderPassDescriptorBase* CreateRenderPassDescriptor(
-            RenderPassDescriptorBuilder* builder) override;
 
         Serial GetCompletedCommandSerial() const final override;
         Serial GetLastSubmittedCommandSerial() const final override;
diff --git a/src/dawn_native/vulkan/Forward.h b/src/dawn_native/vulkan/Forward.h
index 53da58d..99cc23a 100644
--- a/src/dawn_native/vulkan/Forward.h
+++ b/src/dawn_native/vulkan/Forward.h
@@ -29,7 +29,6 @@
     class InputState;
     class PipelineLayout;
     class Queue;
-    using RenderPassDescriptor = RenderPassDescriptorBase;
     class RenderPipeline;
     class Sampler;
     class ShaderModule;
@@ -49,7 +48,6 @@
         using InputStateType = InputState;
         using PipelineLayoutType = PipelineLayout;
         using QueueType = Queue;
-        using RenderPassDescriptorType = RenderPassDescriptor;
         using RenderPipelineType = RenderPipeline;
         using SamplerType = Sampler;
         using ShaderModuleType = ShaderModule;
diff --git a/src/tests/end2end/BindGroupTests.cpp b/src/tests/end2end/BindGroupTests.cpp
index c11b3db..a1a2dcf 100644
--- a/src/tests/end2end/BindGroupTests.cpp
+++ b/src/tests/end2end/BindGroupTests.cpp
@@ -153,7 +153,7 @@
     });
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
     pass.SetPipeline(pipeline);
     pass.SetBindGroup(0, bindGroup);
     pass.Draw(3, 1, 0, 0);
@@ -273,7 +273,7 @@
     dawn::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, 0, {0, 0, 0});
     dawn::Extent3D copySize = {width, height, 1};
     encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copySize);
-    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
     pass.SetPipeline(pipeline);
     pass.SetBindGroup(0, bindGroup);
     pass.Draw(3, 1, 0, 0);
@@ -368,7 +368,7 @@
     }
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
     pass.SetPipeline(pipeline);
     pass.SetBindGroup(0, bindGroups[0]);
     pass.SetBindGroup(1, bindGroups[1]);
@@ -435,7 +435,7 @@
 
     dawn::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
 
     pass.SetPipeline(pipeline);
 
diff --git a/src/tests/end2end/ColorStateTests.cpp b/src/tests/end2end/ColorStateTests.cpp
index bceeaf8..3ed1967 100644
--- a/src/tests/end2end/ColorStateTests.cpp
+++ b/src/tests/end2end/ColorStateTests.cpp
@@ -113,7 +113,7 @@
 
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
         {
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
             // First use the base pipeline to draw a triangle with no blending
             pass.SetPipeline(basePipeline);
             pass.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({{base}})));
@@ -733,7 +733,7 @@
 
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
         {
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
             pass.SetPipeline(testPipeline);
             pass.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({{base}})));
             pass.Draw(3, 1, 0, 0);
@@ -769,18 +769,8 @@
         renderTargetViews[i] = renderTargets[i].CreateDefaultTextureView();
     }
 
-    dawn::RenderPassColorAttachmentDescriptor colorAttachments[4];
-    for (uint32_t i = 0; i < 4; ++i) {
-        colorAttachments[i].attachment = renderTargetViews[i];
-        colorAttachments[i].resolveTarget = nullptr;
-        colorAttachments[i].clearColor = {0.0f, 0.0f, 0.0f, 0.0f};
-        colorAttachments[i].loadOp = dawn::LoadOp::Clear;
-        colorAttachments[i].storeOp = dawn::StoreOp::Store;
-    }
-
-    dawn::RenderPassDescriptor renderpass = device.CreateRenderPassDescriptorBuilder()
-                                                .SetColorAttachments(4, colorAttachments)
-                                                .GetResult();
+    utils::ComboRenderPassDescriptor renderPass({renderTargetViews[0], renderTargetViews[1],
+                                                renderTargetViews[2], renderTargetViews[3]});
 
     dawn::ShaderModule fsModule = utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
         #version 450
@@ -859,7 +849,7 @@
 
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
         {
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
             pass.SetPipeline(basePipeline);
             pass.SetBindGroup(
                 0, MakeBindGroupForColors(std::array<RGBA8, 4>({{base, base, base, base}})));
@@ -933,7 +923,7 @@
     {
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
         {
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
             pass.SetPipeline(basePipeline);
             pass.SetBindGroup(0,
                               MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(0, 0, 0, 0)}})));
@@ -955,7 +945,7 @@
     {
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
         {
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
             pass.SetPipeline(basePipeline);
             pass.SetBindGroup(0,
                               MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(0, 0, 0, 0)}})));
@@ -979,7 +969,7 @@
     {
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
         {
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
             pass.SetPipeline(basePipeline);
             pass.SetBindGroup(0,
                               MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(0, 0, 0, 0)}})));
@@ -992,7 +982,7 @@
             pass.EndPass();
         }
         {
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
             pass.SetPipeline(basePipeline);
             pass.SetBindGroup(0,
                               MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(0, 0, 0, 0)}})));
diff --git a/src/tests/end2end/DebugMarkerTests.cpp b/src/tests/end2end/DebugMarkerTests.cpp
index d38a273..81c3a7d 100644
--- a/src/tests/end2end/DebugMarkerTests.cpp
+++ b/src/tests/end2end/DebugMarkerTests.cpp
@@ -24,7 +24,7 @@
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.PushDebugGroup("Event Start");
         pass.InsertDebugMarker("Marker");
         pass.PopDebugGroup();
diff --git a/src/tests/end2end/DepthStencilStateTests.cpp b/src/tests/end2end/DepthStencilStateTests.cpp
index 6fcdf08..87f617d 100644
--- a/src/tests/end2end/DepthStencilStateTests.cpp
+++ b/src/tests/end2end/DepthStencilStateTests.cpp
@@ -53,26 +53,6 @@
 
             depthTextureView = depthTexture.CreateDefaultTextureView();
 
-            dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-            colorAttachment.attachment = renderTargetView;
-            colorAttachment.resolveTarget = nullptr;
-            colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-            colorAttachment.loadOp = dawn::LoadOp::Clear;
-            colorAttachment.storeOp = dawn::StoreOp::Store;
-
-            dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
-            depthStencilAttachment.attachment = depthTextureView;
-            depthStencilAttachment.depthLoadOp = dawn::LoadOp::Clear;
-            depthStencilAttachment.stencilLoadOp = dawn::LoadOp::Clear;
-            depthStencilAttachment.clearDepth = 1.0f;
-            depthStencilAttachment.clearStencil = 0;
-            depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
-            depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
-            renderpass = device.CreateRenderPassDescriptorBuilder()
-                .SetColorAttachments(1, &colorAttachment)
-                .SetDepthStencilAttachment(&depthStencilAttachment)
-                .GetResult();
-
             vsModule = utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, R"(
                 #version 450
                 layout(set = 0, binding = 0) uniform myBlock {
@@ -273,7 +253,8 @@
                 float depth;
             };
 
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+            utils::ComboRenderPassDescriptor renderPass({renderTargetView}, depthTextureView);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
 
             for (size_t i = 0; i < testParams.size(); ++i) {
                 const TestSpec& test = testParams[i];
@@ -318,7 +299,6 @@
             DoTest(testParams, expected, expected);
         }
 
-        dawn::RenderPassDescriptor renderpass;
         dawn::Texture renderTarget;
         dawn::Texture depthTexture;
         dawn::TextureView renderTargetView;
diff --git a/src/tests/end2end/DrawIndexedTests.cpp b/src/tests/end2end/DrawIndexedTests.cpp
index 821be2e..f3fa3d7 100644
--- a/src/tests/end2end/DrawIndexedTests.cpp
+++ b/src/tests/end2end/DrawIndexedTests.cpp
@@ -97,7 +97,8 @@
             uint32_t zeroOffset = 0;
             dawn::CommandEncoder encoder = device.CreateCommandEncoder();
             {
-                dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+                dawn::RenderPassEncoder pass = encoder.BeginRenderPass(
+                    &renderPass.renderPassInfo);
                 pass.SetPipeline(pipeline);
                 pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
                 pass.SetIndexBuffer(indexBuffer, 0);
diff --git a/src/tests/end2end/DrawTests.cpp b/src/tests/end2end/DrawTests.cpp
index 0a719b1..34c7315 100644
--- a/src/tests/end2end/DrawTests.cpp
+++ b/src/tests/end2end/DrawTests.cpp
@@ -88,7 +88,7 @@
         uint32_t zeroOffset = 0;
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
         {
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
             pass.SetPipeline(pipeline);
             pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
             pass.Draw(vertexCount, instanceCount, firstIndex, firstInstance);
diff --git a/src/tests/end2end/IndexFormatTests.cpp b/src/tests/end2end/IndexFormatTests.cpp
index 2868cba..3eda329 100644
--- a/src/tests/end2end/IndexFormatTests.cpp
+++ b/src/tests/end2end/IndexFormatTests.cpp
@@ -93,7 +93,7 @@
     uint32_t zeroOffset = 0;
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPipeline(pipeline);
         pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
         pass.SetIndexBuffer(indexBuffer, 0);
@@ -124,7 +124,7 @@
     uint32_t zeroOffset = 0;
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPipeline(pipeline);
         pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
         pass.SetIndexBuffer(indexBuffer, 0);
@@ -168,7 +168,7 @@
     uint32_t zeroOffset = 0;
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPipeline(pipeline);
         pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
         pass.SetIndexBuffer(indexBuffer, 0);
@@ -204,7 +204,7 @@
     uint32_t zeroOffset = 0;
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPipeline(pipeline);
         pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
         pass.SetIndexBuffer(indexBuffer, 0);
@@ -243,7 +243,7 @@
     uint32_t zeroOffset = 0;
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPipeline(pipeline16);
         pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
         pass.SetIndexBuffer(indexBuffer, 0);
@@ -278,7 +278,7 @@
     uint32_t zeroOffset = 0;
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetIndexBuffer(indexBuffer, 0);
         pass.SetPipeline(pipeline);
         pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
diff --git a/src/tests/end2end/InputStateTests.cpp b/src/tests/end2end/InputStateTests.cpp
index 20cb923..ffccd54 100644
--- a/src/tests/end2end/InputStateTests.cpp
+++ b/src/tests/end2end/InputStateTests.cpp
@@ -180,7 +180,7 @@
 
             dawn::CommandEncoder encoder = device.CreateCommandEncoder();
 
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
             pass.SetPipeline(pipeline);
 
             uint32_t zeroOffset = 0;
@@ -454,7 +454,7 @@
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
 
-    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
 
     uint32_t zeroOffset = 0;
     pass.SetVertexBuffers(0, 1, &buffer, &zeroOffset);
@@ -499,7 +499,7 @@
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
 
-    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
 
     uint32_t zeroOffset = 0;
     pass.SetVertexBuffers(0, 1, &buffer, &zeroOffset);
diff --git a/src/tests/end2end/PrimitiveTopologyTests.cpp b/src/tests/end2end/PrimitiveTopologyTests.cpp
index f0562c6..ff50737 100644
--- a/src/tests/end2end/PrimitiveTopologyTests.cpp
+++ b/src/tests/end2end/PrimitiveTopologyTests.cpp
@@ -210,7 +210,8 @@
             static const uint32_t zeroOffset = 0;
             dawn::CommandEncoder encoder = device.CreateCommandEncoder();
             {
-                dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+                dawn::RenderPassEncoder pass = encoder.BeginRenderPass(
+                    &renderPass.renderPassInfo);
                 pass.SetPipeline(pipeline);
                 pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
                 pass.Draw(6, 1, 0, 0);
diff --git a/src/tests/end2end/PushConstantTests.cpp b/src/tests/end2end/PushConstantTests.cpp
index b183c3a..c425ff6 100644
--- a/src/tests/end2end/PushConstantTests.cpp
+++ b/src/tests/end2end/PushConstantTests.cpp
@@ -251,7 +251,7 @@
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         // Test render push constants are set to zero by default.
         pass.SetPipeline(pipeline);
         pass.Draw(1, 1, 0, 0);
@@ -378,7 +378,7 @@
     uint32_t two = 2;
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPushConstants(dawn::ShaderStageBit::Vertex, 0, 1, &one);
         pass.SetPushConstants(dawn::ShaderStageBit::Fragment, 0, 1, &two);
         pass.SetPipeline(pipeline);
@@ -404,7 +404,7 @@
     uint32_t two = 2;
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPushConstants(dawn::ShaderStageBit::Vertex | dawn::ShaderStageBit::Fragment, 0, 1, &two);
         pass.SetPipeline(pipeline);
         pass.Draw(1, 1, 0, 0);
diff --git a/src/tests/end2end/RenderPassLoadOpTests.cpp b/src/tests/end2end/RenderPassLoadOpTests.cpp
index d70812d..e8cc3aa 100644
--- a/src/tests/end2end/RenderPassLoadOpTests.cpp
+++ b/src/tests/end2end/RenderPassLoadOpTests.cpp
@@ -112,31 +112,17 @@
 
 // Tests clearing, loading, and drawing into color attachments
 TEST_P(RenderPassLoadOpTests, ColorClearThenLoadAndDraw) {
-    dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-    colorAttachment.attachment = renderTargetView;
-    colorAttachment.resolveTarget = nullptr;
-    colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-    colorAttachment.loadOp = dawn::LoadOp::Clear;
-    colorAttachment.storeOp = dawn::StoreOp::Store;
-
     // Part 1: clear once, check to make sure it's cleared
-    auto renderPassClearZero = device.CreateRenderPassDescriptorBuilder()
-        .SetColorAttachments(1, &colorAttachment)
-        .GetResult();
-
+    utils::ComboRenderPassDescriptor renderPassClearZero({renderTargetView});
     auto commandsClearZeroEncoder = device.CreateCommandEncoder();
-    auto clearZeroPass = commandsClearZeroEncoder.BeginRenderPass(renderPassClearZero);
+    auto clearZeroPass = commandsClearZeroEncoder.BeginRenderPass(&renderPassClearZero);
     clearZeroPass.EndPass();
     auto commandsClearZero = commandsClearZeroEncoder.Finish();
 
-    dawn::RenderPassColorAttachmentDescriptor colorAttachmentGreen = colorAttachment;
-    colorAttachmentGreen.clearColor = { 0.0f, 1.0f, 0.0f, 1.0f };
-    auto renderPassClearGreen = device.CreateRenderPassDescriptorBuilder()
-        .SetColorAttachments(1, &colorAttachmentGreen)
-        .GetResult();
-
+    utils::ComboRenderPassDescriptor renderPassClearGreen({renderTargetView});
+    renderPassClearGreen.cColorAttachmentsInfoPtr[0]->clearColor = {0.0f, 1.0f, 0.0f, 1.0f};
     auto commandsClearGreenEncoder = device.CreateCommandEncoder();
-    auto clearGreenPass = commandsClearGreenEncoder.BeginRenderPass(renderPassClearGreen);
+    auto clearGreenPass = commandsClearGreenEncoder.BeginRenderPass(&renderPassClearGreen);
     clearGreenPass.EndPass();
     auto commandsClearGreen = commandsClearGreenEncoder.Finish();
 
@@ -147,16 +133,12 @@
     EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize, kRTSize, 0, 0);
 
     // Part 2: draw a blue quad into the right half of the render target, and check result
-    dawn::RenderPassColorAttachmentDescriptor colorAttachmentLoad = colorAttachment;
-    colorAttachmentLoad.loadOp = dawn::LoadOp::Load;
-    auto renderPassLoad = device.CreateRenderPassDescriptorBuilder()
-        .SetColorAttachments(1, &colorAttachmentLoad)
-        .GetResult();
-
+    utils::ComboRenderPassDescriptor renderPassLoad({renderTargetView});
+    renderPassLoad.cColorAttachmentsInfoPtr[0]->loadOp = dawn::LoadOp::Load;
     dawn::CommandBuffer commandsLoad;
     {
         auto encoder = device.CreateCommandEncoder();
-        auto pass = encoder.BeginRenderPass(renderPassLoad);
+        auto pass = encoder.BeginRenderPass(&renderPassLoad);
         blueQuad.Draw(&pass);
         pass.EndPass();
         commandsLoad = encoder.Finish();
diff --git a/src/tests/end2end/RenderPassTests.cpp b/src/tests/end2end/RenderPassTests.cpp
index 9abf251..6ceb8ae 100644
--- a/src/tests/end2end/RenderPassTests.cpp
+++ b/src/tests/end2end/RenderPassTests.cpp
@@ -82,22 +82,13 @@
     dawn::Texture renderTarget2 = CreateDefault2DTexture();
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
 
-    dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-    colorAttachment.loadOp = dawn::LoadOp::Clear;
-    colorAttachment.storeOp = dawn::StoreOp::Store;
-    colorAttachment.resolveTarget = nullptr;
-
     {
         // In the first render pass we clear renderTarget1 to red and draw a blue triangle in the
         // bottom left of renderTarget1.
-        colorAttachment.clearColor = { 1.0, 0.0, 0.0, 1.0 };
+        utils::ComboRenderPassDescriptor renderPass({renderTarget1.CreateDefaultTextureView()});
+        renderPass.cColorAttachmentsInfoPtr[0]->clearColor = {1.0f, 0.0f, 0.0f, 1.0f};
 
-        colorAttachment.attachment = renderTarget1.CreateDefaultTextureView();
-        dawn::RenderPassDescriptor renderPass = device.CreateRenderPassDescriptorBuilder()
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
-
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(pipeline);
         pass.Draw(3, 1, 0, 0);
         pass.EndPass();
@@ -106,13 +97,10 @@
     {
         // In the second render pass we clear renderTarget2 to green and draw a blue triangle in the
         // bottom left of renderTarget2.
-        colorAttachment.attachment = renderTarget2.CreateDefaultTextureView();
-        colorAttachment.clearColor = { 0.0, 1.0, 0.0, 1.0 };
-        dawn::RenderPassDescriptor renderPass = device.CreateRenderPassDescriptorBuilder()
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({renderTarget2.CreateDefaultTextureView()});
+        renderPass.cColorAttachmentsInfoPtr[0]->clearColor = {0.0f, 1.0f, 0.0f, 1.0f};
 
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(pipeline);
         pass.Draw(3, 1, 0, 0);
         pass.EndPass();
diff --git a/src/tests/end2end/SamplerTests.cpp b/src/tests/end2end/SamplerTests.cpp
index f6baecd..760f47a 100644
--- a/src/tests/end2end/SamplerTests.cpp
+++ b/src/tests/end2end/SamplerTests.cpp
@@ -140,7 +140,7 @@
 
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
         {
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(mRenderPass.renderPassInfo);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&mRenderPass.renderPassInfo);
             pass.SetPipeline(mPipeline);
             pass.SetBindGroup(0, bindGroup);
             pass.Draw(6, 1, 0, 0);
diff --git a/src/tests/end2end/ScissorTests.cpp b/src/tests/end2end/ScissorTests.cpp
index 0c5f8f7..c564418 100644
--- a/src/tests/end2end/ScissorTests.cpp
+++ b/src/tests/end2end/ScissorTests.cpp
@@ -53,7 +53,7 @@
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPipeline(pipeline);
         pass.Draw(6, 1, 0, 0);
         pass.EndPass();
@@ -75,7 +75,7 @@
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPipeline(pipeline);
         pass.SetScissorRect(0, 0, 200, 200);
         pass.Draw(6, 1, 0, 0);
@@ -101,7 +101,7 @@
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPipeline(pipeline);
         pass.SetScissorRect(0, 0, 0, 0);
         pass.Draw(6, 1, 0, 0);
@@ -129,7 +129,7 @@
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPipeline(pipeline);
         pass.SetScissorRect(kX, kY, kW, kH);
         pass.Draw(6, 1, 0, 0);
@@ -155,13 +155,13 @@
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     // RenderPass 1 set the scissor
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetScissorRect(0, 0, 0, 0);
         pass.EndPass();
     }
     // RenderPass 2 draw a full quad, it shouldn't be scissored
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPipeline(pipeline);
         pass.Draw(6, 1, 0, 0);
         pass.EndPass();
diff --git a/src/tests/end2end/TextureViewTests.cpp b/src/tests/end2end/TextureViewTests.cpp
index aec50ee..94720e2 100644
--- a/src/tests/end2end/TextureViewTests.cpp
+++ b/src/tests/end2end/TextureViewTests.cpp
@@ -178,7 +178,7 @@
 
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
         {
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(mRenderPass.renderPassInfo);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&mRenderPass.renderPassInfo);
             pass.SetPipeline(pipeline);
             pass.SetBindGroup(0, bindGroup);
             pass.Draw(6, 1, 0, 0);
@@ -492,15 +492,8 @@
         dawn::ShaderModule vsModule = CreateDefaultVertexShaderModule(device);
 
         // Clear textureView with Red(255, 0, 0, 255) and render Green(0, 255, 0, 255) into it
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = textureView;
-        colorAttachment.resolveTarget = nullptr;
-        colorAttachment.clearColor = { 1.0, 0.0, 0.0, 1.0 };
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-        dawn::RenderPassDescriptor renderPassInfo = device.CreateRenderPassDescriptorBuilder()
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPassInfo({textureView});
+        renderPassInfo.cColorAttachmentsInfoPtr[0]->clearColor = {1.0f, 0.0f, 0.0f, 1.0f};
 
         const char* oneColorFragmentShader = R"(
             #version 450
@@ -522,8 +515,7 @@
 
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
         {
-            dawn::RenderPassEncoder pass =
-                encoder.BeginRenderPass(renderPassInfo);
+            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassInfo);
             pass.SetPipeline(oneColorPipeline);
             pass.Draw(6, 1, 0, 0);
             pass.EndPass();
diff --git a/src/tests/end2end/ViewportOrientationTests.cpp b/src/tests/end2end/ViewportOrientationTests.cpp
index f1f3295..b23d4d1 100644
--- a/src/tests/end2end/ViewportOrientationTests.cpp
+++ b/src/tests/end2end/ViewportOrientationTests.cpp
@@ -46,7 +46,7 @@
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.SetPipeline(pipeline);
         pass.Draw(1, 1, 0, 0);
         pass.EndPass();
diff --git a/src/tests/unittests/validation/CommandBufferValidationTests.cpp b/src/tests/unittests/validation/CommandBufferValidationTests.cpp
index f7efbf6..3135ba1 100644
--- a/src/tests/unittests/validation/CommandBufferValidationTests.cpp
+++ b/src/tests/unittests/validation/CommandBufferValidationTests.cpp
@@ -26,12 +26,12 @@
 
 // Test that a command buffer cannot be ended mid render pass
 TEST_F(CommandBufferValidationTest, EndedMidRenderPass) {
-    dawn::RenderPassDescriptor renderpass = CreateSimpleRenderPass();
+    DummyRenderPass dummyRenderPass(device);
 
     // Control case, command buffer ended after the pass is ended.
     {
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
         pass.EndPass();
         encoder.Finish();
     }
@@ -39,7 +39,7 @@
     // Error case, command buffer ended mid-pass.
     {
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
         ASSERT_DEVICE_ERROR(encoder.Finish());
     }
 
@@ -47,7 +47,7 @@
     // should fail too.
     {
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
         ASSERT_DEVICE_ERROR(encoder.Finish());
         // TODO(cwallez@chromium.org) this should probably be a device error, but currently it
         // produces a encoder error.
@@ -86,12 +86,12 @@
 
 // Test that a render pass cannot be ended twice
 TEST_F(CommandBufferValidationTest, RenderPassEndedTwice) {
-    dawn::RenderPassDescriptor renderpass = CreateSimpleRenderPass();
+    DummyRenderPass dummyRenderPass(device);
 
     // Control case, pass is ended once
     {
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
         pass.EndPass();
         encoder.Finish();
     }
@@ -99,7 +99,7 @@
     // Error case, pass ended twice
     {
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
         pass.EndPass();
         // TODO(cwallez@chromium.org) this should probably be a device error, but currently it
         // produces a encoder error.
@@ -141,8 +141,8 @@
     // Use the buffer as both index and vertex in the same pass
     uint32_t zero = 0;
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-    auto renderpass = CreateSimpleRenderPass();
-    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+    DummyRenderPass dummyRenderPass(device);
+    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
     pass.SetIndexBuffer(buffer, 0);
     pass.SetVertexBuffers(0, 1, &buffer, &zero);
     pass.EndPass();
@@ -165,8 +165,8 @@
 
     // Use the buffer as both index and storage in the same pass
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-    auto renderpass = CreateSimpleRenderPass();
-    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+    DummyRenderPass dummyRenderPass(device);
+    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
     pass.SetIndexBuffer(buffer, 0);
     pass.SetBindGroup(0, bg);
     pass.EndPass();
@@ -194,19 +194,11 @@
     dawn::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}});
 
     // Create the render pass that will use the texture as an output attachment
-    dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-    colorAttachment.attachment = view;
-    colorAttachment.resolveTarget = nullptr;
-    colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-    colorAttachment.loadOp = dawn::LoadOp::Load;
-    colorAttachment.storeOp = dawn::StoreOp::Store;
-    dawn::RenderPassDescriptor renderPass = device.CreateRenderPassDescriptorBuilder()
-        .SetColorAttachments(1, &colorAttachment)
-        .GetResult();
+    utils::ComboRenderPassDescriptor renderPass({view});
 
     // Use the texture as both sampeld and output attachment in the same pass
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass);
+    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
     pass.SetBindGroup(0, bg);
     pass.EndPass();
     ASSERT_DEVICE_ERROR(encoder.Finish());
diff --git a/src/tests/unittests/validation/DebugMarkerValidationTests.cpp b/src/tests/unittests/validation/DebugMarkerValidationTests.cpp
index 7c0633a..9993cee 100644
--- a/src/tests/unittests/validation/DebugMarkerValidationTests.cpp
+++ b/src/tests/unittests/validation/DebugMarkerValidationTests.cpp
@@ -20,11 +20,11 @@
 
 // Correct usage of debug markers should succeed in render pass.
 TEST_F(DebugMarkerValidationTest, RenderSuccess) {
-    utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 4, 4);
+    DummyRenderPass renderPass(device);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.PushDebugGroup("Event Start");
         pass.PushDebugGroup("Event Start");
         pass.InsertDebugMarker("Marker");
@@ -38,11 +38,11 @@
 
 // A PushDebugGroup call without a following PopDebugGroup produces an error in render pass.
 TEST_F(DebugMarkerValidationTest, RenderUnbalancedPush) {
-    utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 4, 4);
+    DummyRenderPass renderPass(device);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.PushDebugGroup("Event Start");
         pass.PushDebugGroup("Event Start");
         pass.InsertDebugMarker("Marker");
@@ -55,11 +55,11 @@
 
 // A PopDebugGroup call without a preceding PushDebugGroup produces an error in render pass.
 TEST_F(DebugMarkerValidationTest, RenderUnbalancedPop) {
-    utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 4, 4);
+    DummyRenderPass renderPass(device);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.PushDebugGroup("Event Start");
         pass.InsertDebugMarker("Marker");
         pass.PopDebugGroup();
diff --git a/src/tests/unittests/validation/DynamicStateCommandValidationTests.cpp b/src/tests/unittests/validation/DynamicStateCommandValidationTests.cpp
index 3d426ab..0777035 100644
--- a/src/tests/unittests/validation/DynamicStateCommandValidationTests.cpp
+++ b/src/tests/unittests/validation/DynamicStateCommandValidationTests.cpp
@@ -19,11 +19,11 @@
 
 // Test to check basic use of SetScissor
 TEST_F(SetScissorRectTest, Success) {
-    DummyRenderPass renderPass = CreateDummyRenderPass();
+    DummyRenderPass renderPass(device);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetScissorRect(0, 0, 1, 1);
         pass.EndPass();
     }
@@ -32,11 +32,11 @@
 
 // Test to check that an empty scissor is allowed
 TEST_F(SetScissorRectTest, EmptyScissor) {
-    DummyRenderPass renderPass = CreateDummyRenderPass();
+    DummyRenderPass renderPass(device);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetScissorRect(0, 0, 0, 0);
         pass.EndPass();
     }
@@ -47,11 +47,11 @@
 // TODO(cwallez@chromium.org): scissor values seem to be integers in all APIs do the same
 // and test negative values?
 TEST_F(SetScissorRectTest, ScissorLargerThanFramebuffer) {
-    DummyRenderPass renderPass = CreateDummyRenderPass();
+    DummyRenderPass renderPass(device);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetScissorRect(0, 0, renderPass.width + 1, renderPass.height + 1);
         pass.EndPass();
     }
@@ -63,11 +63,11 @@
 
 // Test to check basic use of SetBlendColor
 TEST_F(SetBlendColorTest, Success) {
-    DummyRenderPass renderPass = CreateDummyRenderPass();
+    DummyRenderPass renderPass(device);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         constexpr dawn::Color kTransparentBlack{0.0f, 0.0f, 0.0f, 0.0f};
         pass.SetBlendColor(&kTransparentBlack);
         pass.EndPass();
@@ -77,11 +77,11 @@
 
 // Test that SetBlendColor allows any value, large, small or negative
 TEST_F(SetBlendColorTest, AnyValueAllowed) {
-    DummyRenderPass renderPass = CreateDummyRenderPass();
+    DummyRenderPass renderPass(device);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         constexpr dawn::Color kAnyColorValue{-1.0f, 42.0f, -0.0f, 0.0f};
         pass.SetBlendColor(&kAnyColorValue);
         pass.EndPass();
@@ -94,11 +94,11 @@
 
 // Test to check basic use of SetStencilReferenceTest
 TEST_F(SetStencilReferenceTest, Success) {
-    DummyRenderPass renderPass = CreateDummyRenderPass();
+    DummyRenderPass renderPass(device);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetStencilReference(0);
         pass.EndPass();
     }
@@ -107,11 +107,11 @@
 
 // Test that SetStencilReference allows any bit to be set
 TEST_F(SetStencilReferenceTest, AllBitsAllowed) {
-    DummyRenderPass renderPass = CreateDummyRenderPass();
+    DummyRenderPass renderPass(device);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetStencilReference(0xFFFFFFFF);
         pass.EndPass();
     }
diff --git a/src/tests/unittests/validation/PushConstantsValidationTests.cpp b/src/tests/unittests/validation/PushConstantsValidationTests.cpp
index 9b03080..030deae 100644
--- a/src/tests/unittests/validation/PushConstantsValidationTests.cpp
+++ b/src/tests/unittests/validation/PushConstantsValidationTests.cpp
@@ -44,7 +44,7 @@
 
 // Test valid usage of the parameters to SetPushConstants
 TEST_F(PushConstantTest, Success) {
-    DummyRenderPass renderpassData = CreateDummyRenderPass();
+    DummyRenderPass renderpassData(device);
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     // PushConstants in a compute pass
@@ -56,7 +56,7 @@
 
     // PushConstants in a render pass
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpassData.renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderpassData);
         pass.SetPushConstants(dawn::ShaderStageBit::Vertex | dawn::ShaderStageBit::Fragment, 0, 1, constants);
         pass.EndPass();
     }
@@ -142,12 +142,12 @@
 
 // Test valid stages for render passes
 TEST_F(PushConstantTest, StageForRenderPass) {
-    DummyRenderPass renderpassData = CreateDummyRenderPass();
+    DummyRenderPass renderpassData(device);
 
     // Control case: setting to vertex and fragment in render pass
     {
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpassData.renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderpassData);
         pass.SetPushConstants(dawn::ShaderStageBit::Vertex | dawn::ShaderStageBit::Fragment, 0, 1, constants);
         pass.EndPass();
         encoder.Finish();
@@ -156,7 +156,7 @@
     // Compute stage is disallowed
     {
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpassData.renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderpassData);
         pass.SetPushConstants(dawn::ShaderStageBit::Compute, 0, 1, constants);
         pass.EndPass();
         ASSERT_DEVICE_ERROR(encoder.Finish());
@@ -165,7 +165,7 @@
     // A None shader stage mask is valid.
     {
         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpassData.renderPass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderpassData);
         pass.SetPushConstants(dawn::ShaderStageBit::None, 0, 1, constants);
         pass.EndPass();
         encoder.Finish();
diff --git a/src/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp b/src/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
index b2c08a7..03c4e5e 100644
--- a/src/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
+++ b/src/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
@@ -16,9 +16,28 @@
 
 #include "common/Constants.h"
 
+#include "utils/DawnHelpers.h"
+
 namespace {
 
 class RenderPassDescriptorValidationTest : public ValidationTest {
+  public:
+    void AssertBeginRenderPassSuccess(const dawn::RenderPassDescriptor* descriptor) {
+        dawn::CommandEncoder commandEncoder = TestBeginRenderPass(descriptor);
+        commandEncoder.Finish();
+    }
+    void AssertBeginRenderPassError(const dawn::RenderPassDescriptor* descriptor) {
+        dawn::CommandEncoder commandEncoder = TestBeginRenderPass(descriptor);
+        ASSERT_DEVICE_ERROR(commandEncoder.Finish());
+    }
+
+  private:
+    dawn::CommandEncoder TestBeginRenderPass(const dawn::RenderPassDescriptor* descriptor) {
+        dawn::CommandEncoder commandEncoder = device.CreateCommandEncoder();
+        dawn::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(descriptor);
+        renderPassEncoder.EndPass();
+        return commandEncoder;
+    }
 };
 
 dawn::Texture CreateTexture(dawn::Device& device,
@@ -51,10 +70,10 @@
     return texture.CreateDefaultTextureView();
 }
 
-// A render pass with no attachments isn't valid
-TEST_F(RenderPassDescriptorValidationTest, Empty) {
-    AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
-        .GetResult();
+// Using BeginRenderPass with no attachments isn't valid
+TEST_F(RenderPassDescriptorValidationTest, Empty) {  
+    utils::ComboRenderPassDescriptor renderPass({}, nullptr);
+    AssertBeginRenderPassError(&renderPass);
 }
 
 // A render pass with only one color or one depth attachment is ok
@@ -62,60 +81,67 @@
     // One color attachment
     {
         dawn::TextureView color = Create2DAttachment(device, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm);
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = color;
-        colorAttachment.resolveTarget = nullptr;
-        colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({color});
+
+        AssertBeginRenderPassSuccess(&renderPass);
     }
     // One depth-stencil attachment
     {
         dawn::TextureView depthStencil = Create2DAttachment(device, 1, 1, dawn::TextureFormat::D32FloatS8Uint);
-        dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
-        depthStencilAttachment.attachment = depthStencil;
-        depthStencilAttachment.depthLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.stencilLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.clearDepth = 1.0f;
-        depthStencilAttachment.clearStencil = 0;
-        depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
-        depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetDepthStencilAttachment(&depthStencilAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({}, depthStencil);
+
+        AssertBeginRenderPassSuccess(&renderPass);
     }
 }
 
 // Test OOB color attachment indices are handled
 TEST_F(RenderPassDescriptorValidationTest, ColorAttachmentOutOfBounds) {
+    dawn::TextureView color1 = Create2DAttachment(device, 1, 1,
+                                                  dawn::TextureFormat::R8G8B8A8Unorm);
+    dawn::TextureView color2 = Create2DAttachment(device, 1, 1,
+                                                  dawn::TextureFormat::R8G8B8A8Unorm);
+    dawn::TextureView color3 = Create2DAttachment(device, 1, 1,
+                                                  dawn::TextureFormat::R8G8B8A8Unorm);
+    dawn::TextureView color4 = Create2DAttachment(device, 1, 1,
+                                                  dawn::TextureFormat::R8G8B8A8Unorm);
     // For setting the color attachment, control case
     {
-        dawn::TextureView color = Create2DAttachment(device, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm);
-        dawn::RenderPassColorAttachmentDescriptor colorAttachments[kMaxColorAttachments];
-        colorAttachments[kMaxColorAttachments - 1].attachment = color;
-        colorAttachments[kMaxColorAttachments - 1].resolveTarget = nullptr;
-        colorAttachments[kMaxColorAttachments - 1].clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachments[kMaxColorAttachments - 1].loadOp = dawn::LoadOp::Clear;
-        colorAttachments[kMaxColorAttachments - 1].storeOp = dawn::StoreOp::Store;
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(kMaxColorAttachments, colorAttachments)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({color1, color2, color3, color4});
+        AssertBeginRenderPassSuccess(&renderPass);
     }
     // For setting the color attachment, OOB
     {
-        dawn::TextureView color = Create2DAttachment(device, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm);
-        dawn::RenderPassColorAttachmentDescriptor colorAttachments[kMaxColorAttachments + 1];
-        colorAttachments[kMaxColorAttachments].attachment = color;
-        colorAttachments[kMaxColorAttachments].resolveTarget = nullptr;
-        colorAttachments[kMaxColorAttachments].clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachments[kMaxColorAttachments].loadOp = dawn::LoadOp::Clear;
-        colorAttachments[kMaxColorAttachments].storeOp = dawn::StoreOp::Store;
-        AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(kMaxColorAttachments + 1, colorAttachments)
-            .GetResult();
+        // We cannot use utils::ComboRenderPassDescriptor here because it only supports at most
+        // kMaxColorAttachments(4) color attachments.
+        dawn::RenderPassColorAttachmentDescriptor colorAttachment1;
+        colorAttachment1.attachment = color1;
+        colorAttachment1.resolveTarget = nullptr;
+        colorAttachment1.clearColor = {0.0f, 0.0f, 0.0f, 0.0f};
+        colorAttachment1.loadOp = dawn::LoadOp::Clear;
+        colorAttachment1.storeOp = dawn::StoreOp::Store;
+
+        dawn::RenderPassColorAttachmentDescriptor colorAttachment2 = colorAttachment1;
+        dawn::RenderPassColorAttachmentDescriptor colorAttachment3 = colorAttachment1;
+        dawn::RenderPassColorAttachmentDescriptor colorAttachment4 = colorAttachment1;
+        colorAttachment2.attachment = color2;
+        colorAttachment3.attachment = color3;
+        colorAttachment4.attachment = color4;
+
+        dawn::TextureView color5 = Create2DAttachment(device, 1, 1,
+                                                      dawn::TextureFormat::R8G8B8A8Unorm);
+        dawn::RenderPassColorAttachmentDescriptor colorAttachment5 = colorAttachment1;
+        colorAttachment5.attachment = color5;
+
+        dawn::RenderPassColorAttachmentDescriptor* colorAttachments[] = {&colorAttachment1,
+                                                                         &colorAttachment2,
+                                                                         &colorAttachment3,
+                                                                         &colorAttachment4,
+                                                                         &colorAttachment5};
+        dawn::RenderPassDescriptor renderPass;
+        renderPass.colorAttachmentCount = kMaxColorAttachments + 1;
+        renderPass.colorAttachments = colorAttachments;
+        renderPass.depthStencilAttachment = nullptr;
+        AssertBeginRenderPassError(&renderPass);
     }
 }
 
@@ -125,82 +151,25 @@
     dawn::TextureView color1x1B = Create2DAttachment(device, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm);
     dawn::TextureView color2x2 = Create2DAttachment(device, 2, 2, dawn::TextureFormat::R8G8B8A8Unorm);
 
-    dawn::RenderPassColorAttachmentDescriptor colorAttachment1x1A;
-    colorAttachment1x1A.attachment = color1x1A;
-    colorAttachment1x1A.resolveTarget = nullptr;
-    colorAttachment1x1A.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-    colorAttachment1x1A.loadOp = dawn::LoadOp::Clear;
-    colorAttachment1x1A.storeOp = dawn::StoreOp::Store;
-
-    dawn::RenderPassColorAttachmentDescriptor colorAttachment1x1B;
-    colorAttachment1x1B.attachment = color1x1B;
-    colorAttachment1x1B.resolveTarget = nullptr;
-    colorAttachment1x1B.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-    colorAttachment1x1B.loadOp = dawn::LoadOp::Clear;
-    colorAttachment1x1B.storeOp = dawn::StoreOp::Store;
-
-    dawn::RenderPassColorAttachmentDescriptor colorAttachment2x2;
-    colorAttachment2x2.attachment = color2x2;
-    colorAttachment2x2.resolveTarget = nullptr;
-    colorAttachment2x2.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-    colorAttachment2x2.loadOp = dawn::LoadOp::Clear;
-    colorAttachment2x2.storeOp = dawn::StoreOp::Store;
-
     dawn::TextureView depthStencil1x1 = Create2DAttachment(device, 1, 1, dawn::TextureFormat::D32FloatS8Uint);
     dawn::TextureView depthStencil2x2 = Create2DAttachment(device, 2, 2, dawn::TextureFormat::D32FloatS8Uint);
 
-    dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment1x1;
-    depthStencilAttachment1x1.attachment = depthStencil1x1;
-    depthStencilAttachment1x1.depthLoadOp = dawn::LoadOp::Clear;
-    depthStencilAttachment1x1.stencilLoadOp = dawn::LoadOp::Clear;
-    depthStencilAttachment1x1.clearDepth = 1.0f;
-    depthStencilAttachment1x1.clearStencil = 0;
-    depthStencilAttachment1x1.depthStoreOp = dawn::StoreOp::Store;
-    depthStencilAttachment1x1.stencilStoreOp = dawn::StoreOp::Store;
-
-    dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment2x2;
-    depthStencilAttachment2x2.attachment = depthStencil2x2;
-    depthStencilAttachment2x2.depthLoadOp = dawn::LoadOp::Clear;
-    depthStencilAttachment2x2.stencilLoadOp = dawn::LoadOp::Clear;
-    depthStencilAttachment2x2.clearDepth = 1.0f;
-    depthStencilAttachment2x2.clearStencil = 0;
-    depthStencilAttachment2x2.depthStoreOp = dawn::StoreOp::Store;
-    depthStencilAttachment2x2.stencilStoreOp = dawn::StoreOp::Store;
-
     // Control case: all the same size (1x1)
     {
-        dawn::RenderPassColorAttachmentDescriptor colorAttachments[2];
-        colorAttachments[0] = colorAttachment1x1A;
-        colorAttachments[1] = colorAttachment1x1B;
-
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(2, colorAttachments)
-            .SetDepthStencilAttachment(&depthStencilAttachment1x1)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({color1x1A, color1x1B}, depthStencil1x1);
+        AssertBeginRenderPassSuccess(&renderPass);
     }
 
     // One of the color attachments has a different size
     {
-        dawn::RenderPassColorAttachmentDescriptor colorAttachments[2];
-        colorAttachments[0] = colorAttachment1x1A;
-        colorAttachments[1] = colorAttachment2x2;
-
-        AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(2, colorAttachments)
-            .SetDepthStencilAttachment(&depthStencilAttachment1x1)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({color1x1A, color2x2});
+        AssertBeginRenderPassError(&renderPass);
     }
 
     // The depth stencil attachment has a different size
     {
-        dawn::RenderPassColorAttachmentDescriptor colorAttachments[2];
-        colorAttachments[0] = colorAttachment1x1A;
-        colorAttachments[1] = colorAttachment1x1B;
-
-        AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(2, colorAttachments)
-            .SetDepthStencilAttachment(&depthStencilAttachment2x2)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({color1x1A, color1x1B}, depthStencil2x2);
+        AssertBeginRenderPassError(&renderPass);
     }
 }
 
@@ -211,31 +180,14 @@
 
     // Using depth-stencil for color
     {
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = depthStencil;
-        colorAttachment.resolveTarget = nullptr;
-        colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-
-        AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({depthStencil});
+        AssertBeginRenderPassError(&renderPass);
     }
 
     // Using color for depth-stencil
     {
-        dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
-        depthStencilAttachment.attachment = color;
-        depthStencilAttachment.depthLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.stencilLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.clearDepth = 1.0f;
-        depthStencilAttachment.clearStencil = 0;
-        depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
-        depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
-        AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
-            .SetDepthStencilAttachment(&depthStencilAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({}, color);
+        AssertBeginRenderPassError(&renderPass);
     }
 }
 
@@ -269,16 +221,8 @@
         descriptor.arrayLayerCount = 5;
 
         dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = colorTextureView;
-        colorAttachment.resolveTarget = nullptr;
-        colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-
-        AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({colorTextureView});
+        AssertBeginRenderPassError(&renderPass);
     }
 
     // Using 2D array texture view with arrayLayerCount > 1 is not allowed for depth stencil
@@ -288,17 +232,8 @@
         descriptor.arrayLayerCount = 5;
 
         dawn::TextureView depthStencilView = depthStencilTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
-        depthStencilAttachment.attachment = depthStencilView;
-        depthStencilAttachment.depthLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.stencilLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.clearDepth = 1.0f;
-        depthStencilAttachment.clearStencil = 0;
-        depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
-        depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
-        AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
-            .SetDepthStencilAttachment(&depthStencilAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
+        AssertBeginRenderPassError(&renderPass);
     }
 
     // Using 2D array texture view that covers the first layer of the texture is OK for color
@@ -309,15 +244,8 @@
         descriptor.arrayLayerCount = 1;
 
         dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = colorTextureView;
-        colorAttachment.resolveTarget = nullptr;
-        colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({colorTextureView});
+        AssertBeginRenderPassSuccess(&renderPass);
     }
 
     // Using 2D array texture view that covers the first layer is OK for depth stencil
@@ -327,19 +255,9 @@
         descriptor.baseArrayLayer = 0;
         descriptor.arrayLayerCount = 1;
 
-        dawn::TextureView depthStencilTextureView =
-            depthStencilTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
-        depthStencilAttachment.attachment = depthStencilTextureView;
-        depthStencilAttachment.depthLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.stencilLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.clearDepth = 1.0f;
-        depthStencilAttachment.clearStencil = 0;
-        depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
-        depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetDepthStencilAttachment(&depthStencilAttachment)
-            .GetResult();
+        dawn::TextureView depthStencilView = depthStencilTexture.CreateTextureView(&descriptor);
+        utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
+        AssertBeginRenderPassSuccess(&renderPass);
     }
 
     // Using 2D array texture view that covers the last layer is OK for color
@@ -350,15 +268,8 @@
         descriptor.arrayLayerCount = 1;
 
         dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = colorTextureView;
-        colorAttachment.resolveTarget = nullptr;
-        colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({colorTextureView});
+        AssertBeginRenderPassSuccess(&renderPass);
     }
 
     // Using 2D array texture view that covers the last layer is OK for depth stencil
@@ -368,19 +279,9 @@
         descriptor.baseArrayLayer = kArrayLayers - 1;
         descriptor.arrayLayerCount = 1;
 
-        dawn::TextureView depthStencilTextureView =
-            depthStencilTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
-        depthStencilAttachment.attachment = depthStencilTextureView;
-        depthStencilAttachment.depthLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.stencilLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.clearDepth = 1.0f;
-        depthStencilAttachment.clearStencil = 0;
-        depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
-        depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetDepthStencilAttachment(&depthStencilAttachment)
-            .GetResult();
+        dawn::TextureView depthStencilView = depthStencilTexture.CreateTextureView(&descriptor);
+        utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
+        AssertBeginRenderPassSuccess(&renderPass);
     }
 }
 
@@ -413,15 +314,8 @@
         descriptor.mipLevelCount = 2;
 
         dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = colorTextureView;
-        colorAttachment.resolveTarget = nullptr;
-        colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-        AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({colorTextureView});
+        AssertBeginRenderPassError(&renderPass);
     }
 
     // Using 2D texture view with mipLevelCount > 1 is not allowed for depth stencil
@@ -431,17 +325,8 @@
         descriptor.mipLevelCount = 2;
 
         dawn::TextureView depthStencilView = depthStencilTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
-        depthStencilAttachment.attachment = depthStencilView;
-        depthStencilAttachment.depthLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.stencilLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.clearDepth = 1.0f;
-        depthStencilAttachment.clearStencil = 0;
-        depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
-        depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
-        AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
-            .SetDepthStencilAttachment(&depthStencilAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
+        AssertBeginRenderPassError(&renderPass);
     }
 
     // Using 2D texture view that covers the first level of the texture is OK for color
@@ -452,15 +337,8 @@
         descriptor.mipLevelCount = 1;
 
         dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = colorTextureView;
-        colorAttachment.resolveTarget = nullptr;
-        colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({colorTextureView});
+        AssertBeginRenderPassSuccess(&renderPass);
     }
 
     // Using 2D texture view that covers the first level is OK for depth stencil
@@ -470,19 +348,9 @@
         descriptor.baseMipLevel = 0;
         descriptor.mipLevelCount = 1;
 
-        dawn::TextureView depthStencilTextureView =
-            depthStencilTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
-        depthStencilAttachment.attachment = depthStencilTextureView;
-        depthStencilAttachment.depthLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.stencilLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.clearDepth = 1.0f;
-        depthStencilAttachment.clearStencil = 0;
-        depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
-        depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetDepthStencilAttachment(&depthStencilAttachment)
-            .GetResult();
+        dawn::TextureView depthStencilView = depthStencilTexture.CreateTextureView(&descriptor);
+        utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
+        AssertBeginRenderPassSuccess(&renderPass);
     }
 
     // Using 2D texture view that covers the last level is OK for color
@@ -493,15 +361,8 @@
         descriptor.mipLevelCount = 1;
 
         dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = colorTextureView;
-        colorAttachment.resolveTarget = nullptr;
-        colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({colorTextureView});
+        AssertBeginRenderPassSuccess(&renderPass);
     }
 
     // Using 2D texture view that covers the last level is OK for depth stencil
@@ -511,19 +372,9 @@
         descriptor.baseMipLevel = kLevelCount - 1;
         descriptor.mipLevelCount = 1;
 
-        dawn::TextureView depthStencilTextureView =
-            depthStencilTexture.CreateTextureView(&descriptor);
-        dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
-        depthStencilAttachment.attachment = depthStencilTextureView;
-        depthStencilAttachment.depthLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.stencilLoadOp = dawn::LoadOp::Clear;
-        depthStencilAttachment.clearDepth = 1.0f;
-        depthStencilAttachment.clearStencil = 0;
-        depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
-        depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
-        AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-            .SetDepthStencilAttachment(&depthStencilAttachment)
-            .GetResult();
+        dawn::TextureView depthStencilView = depthStencilTexture.CreateTextureView(&descriptor);
+        utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
+        AssertBeginRenderPassSuccess(&renderPass);
     }
 }
 
@@ -547,15 +398,9 @@
         dawn::TextureView colorTextureView = colorTexture.CreateDefaultTextureView();
         dawn::TextureView resolveTargetTextureView = resolveTexture.CreateDefaultTextureView();
 
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = colorTextureView;
-        colorAttachment.resolveTarget = resolveTargetTextureView;
-        colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-        AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
+        utils::ComboRenderPassDescriptor renderPass({colorTextureView});
+        renderPass.cColorAttachmentsInfoPtr[0]->resolveTarget = resolveTargetTextureView;
+        AssertBeginRenderPassError(&renderPass);
     }
 }
 
diff --git a/src/tests/unittests/validation/ValidationTest.cpp b/src/tests/unittests/validation/ValidationTest.cpp
index 7c16033..e14a014 100644
--- a/src/tests/unittests/validation/ValidationTest.cpp
+++ b/src/tests/unittests/validation/ValidationTest.cpp
@@ -84,31 +84,6 @@
     return mDeviceErrorMessage;
 }
 
-dawn::RenderPassDescriptor ValidationTest::CreateSimpleRenderPass() {
-        dawn::TextureDescriptor descriptor;
-        descriptor.dimension = dawn::TextureDimension::e2D;
-        descriptor.size.width = 640;
-        descriptor.size.height = 480;
-        descriptor.size.depth = 1;
-        descriptor.arrayLayerCount = 1;
-        descriptor.sampleCount = 1;
-        descriptor.format = dawn::TextureFormat::R8G8B8A8Unorm;
-        descriptor.mipLevelCount = 1;
-        descriptor.usage = dawn::TextureUsageBit::OutputAttachment;
-
-        auto colorBuffer = device.CreateTexture(&descriptor);
-        auto colorView = colorBuffer.CreateDefaultTextureView();
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = colorView;
-        colorAttachment.resolveTarget = nullptr;
-        colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-        return device.CreateRenderPassDescriptorBuilder()
-            .SetColorAttachments(1, &colorAttachment)
-            .GetResult();
-}
-
 void ValidationTest::OnDeviceError(const char* message, dawnCallbackUserdata userdata) {
     auto self = reinterpret_cast<ValidationTest*>(static_cast<uintptr_t>(userdata));
     self->mDeviceErrorMessage = message;
@@ -138,34 +113,30 @@
     expectation.statusMessage = message;
 }
 
-ValidationTest::DummyRenderPass ValidationTest::CreateDummyRenderPass() {
-    DummyRenderPass dummy;
-    dummy.width = 400;
-    dummy.height = 400;
-    dummy.attachmentFormat = dawn::TextureFormat::R8G8B8A8Unorm;
+ValidationTest::DummyRenderPass::DummyRenderPass(const dawn::Device& device)
+    : attachmentFormat(dawn::TextureFormat::R8G8B8A8Unorm), width(400), height(400) {
 
     dawn::TextureDescriptor descriptor;
     descriptor.dimension = dawn::TextureDimension::e2D;
-    descriptor.size.width = dummy.width;
-    descriptor.size.height = dummy.height;
+    descriptor.size.width = width;
+    descriptor.size.height = height;
     descriptor.size.depth = 1;
     descriptor.arrayLayerCount = 1;
     descriptor.sampleCount = 1;
-    descriptor.format = dummy.attachmentFormat;
+    descriptor.format = attachmentFormat;
     descriptor.mipLevelCount = 1;
     descriptor.usage = dawn::TextureUsageBit::OutputAttachment;
-    dummy.attachment = device.CreateTexture(&descriptor);
+    attachment = device.CreateTexture(&descriptor);
 
-    dawn::TextureView view = dummy.attachment.CreateDefaultTextureView();
-    dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-    colorAttachment.attachment = view;
-    colorAttachment.resolveTarget = nullptr;
-    colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
-    colorAttachment.loadOp = dawn::LoadOp::Clear;
-    colorAttachment.storeOp = dawn::StoreOp::Store;
-    dummy.renderPass = AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
-        .SetColorAttachments(1, &colorAttachment)
-        .GetResult();
+    dawn::TextureView view = attachment.CreateDefaultTextureView();
+    mColorAttachment.attachment = view;
+    mColorAttachment.resolveTarget = nullptr;
+    mColorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
+    mColorAttachment.loadOp = dawn::LoadOp::Clear;
+    mColorAttachment.storeOp = dawn::StoreOp::Store;
+    mColorAttachments[0] = &mColorAttachment;
 
-    return dummy;
+    colorAttachmentCount = 1;
+    colorAttachments = mColorAttachments;
+    depthStencilAttachment = nullptr;
 }
diff --git a/src/tests/unittests/validation/ValidationTest.h b/src/tests/unittests/validation/ValidationTest.h
index 3138f6a..10c42e3 100644
--- a/src/tests/unittests/validation/ValidationTest.h
+++ b/src/tests/unittests/validation/ValidationTest.h
@@ -53,18 +53,20 @@
         bool EndExpectDeviceError();
         std::string GetLastDeviceErrorMessage() const;
 
-        dawn::RenderPassDescriptor CreateSimpleRenderPass();
-
         // Helper functions to create objects to test validation.
 
-        struct DummyRenderPass {
-            dawn::RenderPassDescriptor renderPass;
+        struct DummyRenderPass : public dawn::RenderPassDescriptor{
+          public:
+            DummyRenderPass(const dawn::Device& device);
             dawn::Texture attachment;
             dawn::TextureFormat attachmentFormat;
             uint32_t width;
             uint32_t height;
+
+          private:
+            dawn::RenderPassColorAttachmentDescriptor mColorAttachment;
+            dawn::RenderPassColorAttachmentDescriptor* mColorAttachments[1];
         };
-        DummyRenderPass CreateDummyRenderPass();
 
     protected:
         dawn::Device device;
diff --git a/src/tests/unittests/validation/VertexBufferValidationTests.cpp b/src/tests/unittests/validation/VertexBufferValidationTests.cpp
index 7ce83f5..4125c7b 100644
--- a/src/tests/unittests/validation/VertexBufferValidationTests.cpp
+++ b/src/tests/unittests/validation/VertexBufferValidationTests.cpp
@@ -24,8 +24,6 @@
         void SetUp() override {
             ValidationTest::SetUp();
 
-            renderpass = CreateSimpleRenderPass();
-
             fsModule = utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
                 #version 450
                 layout(location = 0) out vec4 fragColor;
@@ -99,11 +97,11 @@
             return device.CreateRenderPipeline(&descriptor);
         }
 
-        dawn::RenderPassDescriptor renderpass;
         dawn::ShaderModule fsModule;
 };
 
 TEST_F(VertexBufferValidationTest, VertexInputsInheritedBetweenPipelines) {
+    DummyRenderPass renderPass(device);
     auto vsModule2 = MakeVertexShader(2);
     auto vsModule1 = MakeVertexShader(1);
 
@@ -119,7 +117,7 @@
     // Check failure when vertex buffer is not set
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(pipeline1);
         pass.Draw(3, 1, 0, 0);
         pass.EndPass();
@@ -129,7 +127,7 @@
     // Check success when vertex buffer is inherited from previous pipeline
     encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(pipeline2);
         pass.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets);
         pass.Draw(3, 1, 0, 0);
@@ -141,6 +139,7 @@
 }
 
 TEST_F(VertexBufferValidationTest, VertexInputsNotInheritedBetweenRendePasses) {
+    DummyRenderPass renderPass(device);
     auto vsModule2 = MakeVertexShader(2);
     auto vsModule1 = MakeVertexShader(1);
 
@@ -156,14 +155,14 @@
     // Check success when vertex buffer is set for each render pass
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(pipeline2);
         pass.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets);
         pass.Draw(3, 1, 0, 0);
         pass.EndPass();
     }
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(pipeline1);
         pass.SetVertexBuffers(0, 1, vertexBuffers.data(), offsets);
         pass.Draw(3, 1, 0, 0);
@@ -174,14 +173,14 @@
     // Check failure because vertex buffer is not inherited in second subpass
     encoder = device.CreateCommandEncoder();
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(pipeline2);
         pass.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets);
         pass.Draw(3, 1, 0, 0);
         pass.EndPass();
     }
     {
-        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderpass);
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
         pass.SetPipeline(pipeline1);
         pass.Draw(3, 1, 0, 0);
         pass.EndPass();
diff --git a/src/tests/unittests/wire/WireArgumentTests.cpp b/src/tests/unittests/wire/WireArgumentTests.cpp
index a459427..98612f0 100644
--- a/src/tests/unittests/wire/WireArgumentTests.cpp
+++ b/src/tests/unittests/wire/WireArgumentTests.cpp
@@ -179,34 +179,31 @@
     FlushClient();
 }
 
+
 // Test that the wire is able to send objects as value arguments
 TEST_F(WireArgumentTests, ObjectAsValueArgument) {
-    // Create a RenderPassDescriptor
-    dawnRenderPassDescriptorBuilder renderPassBuilder =
-        dawnDeviceCreateRenderPassDescriptorBuilder(device);
-    dawnRenderPassDescriptor renderPass =
-        dawnRenderPassDescriptorBuilderGetResult(renderPassBuilder);
-
-    dawnRenderPassDescriptorBuilder apiRenderPassBuilder = api.GetNewRenderPassDescriptorBuilder();
-    EXPECT_CALL(api, DeviceCreateRenderPassDescriptorBuilder(apiDevice))
-        .WillOnce(Return(apiRenderPassBuilder));
-    dawnRenderPassDescriptor apiRenderPass = api.GetNewRenderPassDescriptor();
-    EXPECT_CALL(api, RenderPassDescriptorBuilderGetResult(apiRenderPassBuilder))
-        .WillOnce(Return(apiRenderPass));
-
-    // Create command buffer encoder, setting render pass descriptor
     dawnCommandEncoder cmdBufEncoder = dawnDeviceCreateCommandEncoder(device);
-    dawnCommandEncoderBeginRenderPass(cmdBufEncoder, renderPass);
+    dawnCommandEncoder apiEncoder = api.GetNewCommandEncoder();
+    EXPECT_CALL(api, DeviceCreateCommandEncoder(apiDevice)).WillOnce(Return(apiEncoder));
 
-    dawnCommandEncoder apiCmdBufEncoder = api.GetNewCommandEncoder();
-    EXPECT_CALL(api, DeviceCreateCommandEncoder(apiDevice))
-        .WillOnce(Return(apiCmdBufEncoder));
+    dawnBufferDescriptor descriptor;
+    descriptor.nextInChain = nullptr;
+    descriptor.size = 8;
+    descriptor.usage = static_cast<dawnBufferUsageBit>(DAWN_BUFFER_USAGE_BIT_TRANSFER_SRC |
+                                                       DAWN_BUFFER_USAGE_BIT_TRANSFER_DST);
 
-    EXPECT_CALL(api, CommandEncoderBeginRenderPass(apiCmdBufEncoder, apiRenderPass)).Times(1);
+    dawnBuffer buffer = dawnDeviceCreateBuffer(device, &descriptor);
+    dawnBuffer apiBuffer = api.GetNewBuffer();
+    EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _))
+        .WillOnce(Return(apiBuffer))
+        .RetiresOnSaturation();
 
-    EXPECT_CALL(api, CommandEncoderRelease(apiCmdBufEncoder));
-    EXPECT_CALL(api, RenderPassDescriptorBuilderRelease(apiRenderPassBuilder));
-    EXPECT_CALL(api, RenderPassDescriptorRelease(apiRenderPass));
+    dawnCommandEncoderCopyBufferToBuffer(cmdBufEncoder, buffer, 0, buffer, 4, 4);
+    EXPECT_CALL(api, CommandEncoderCopyBufferToBuffer(apiEncoder, apiBuffer, 0, apiBuffer, 4, 4));
+
+    EXPECT_CALL(api, CommandEncoderRelease(apiEncoder));
+    EXPECT_CALL(api, BufferRelease(apiBuffer));
+
     FlushClient();
 }
 
diff --git a/src/utils/DawnHelpers.cpp b/src/utils/DawnHelpers.cpp
index 40c567d..014bcf1 100644
--- a/src/utils/DawnHelpers.cpp
+++ b/src/utils/DawnHelpers.cpp
@@ -126,14 +126,97 @@
         return buffer;
     }
 
+    ComboRenderPassDescriptor::ComboRenderPassDescriptor(
+        std::initializer_list<dawn::TextureView> colorAttachmentInfo,
+        dawn::TextureView depthStencil)
+        : cColorAttachmentsInfoPtr() {
+        for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
+            mColorAttachmentsInfo[i].loadOp = dawn::LoadOp::Clear;
+            mColorAttachmentsInfo[i].storeOp = dawn::StoreOp::Store;
+            mColorAttachmentsInfo[i].clearColor = {0.0f, 0.0f, 0.0f, 0.0f};
+            cColorAttachmentsInfoPtr[i] = nullptr;
+        }
+
+        cDepthStencilAttachmentInfo.clearDepth = 1.0f;
+        cDepthStencilAttachmentInfo.clearStencil = 0;
+        cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Clear;
+        cDepthStencilAttachmentInfo.depthStoreOp = dawn::StoreOp::Store;
+        cDepthStencilAttachmentInfo.stencilLoadOp = dawn::LoadOp::Clear;
+        cDepthStencilAttachmentInfo.stencilStoreOp = dawn::StoreOp::Store;
+
+        colorAttachmentCount = static_cast<uint32_t>(colorAttachmentInfo.size());
+        uint32_t colorAttachmentIndex = 0;
+        for (const dawn::TextureView& colorAttachment : colorAttachmentInfo) {
+            if (colorAttachment.Get() != nullptr) {
+                mColorAttachmentsInfo[colorAttachmentIndex].attachment = colorAttachment;
+                cColorAttachmentsInfoPtr[colorAttachmentIndex] =
+                    &mColorAttachmentsInfo[colorAttachmentIndex];
+            }
+            ++colorAttachmentIndex;
+        }
+        colorAttachments = cColorAttachmentsInfoPtr;
+
+        if (depthStencil.Get() != nullptr) {
+            cDepthStencilAttachmentInfo.attachment = depthStencil;
+            depthStencilAttachment = &cDepthStencilAttachmentInfo;
+        } else {
+            depthStencilAttachment = nullptr;
+        }
+    }
+
+    const ComboRenderPassDescriptor& ComboRenderPassDescriptor::operator=(
+        const ComboRenderPassDescriptor& otherRenderPass) {
+        cDepthStencilAttachmentInfo = otherRenderPass.cDepthStencilAttachmentInfo;
+        mColorAttachmentsInfo = otherRenderPass.mColorAttachmentsInfo;
+
+        colorAttachmentCount = otherRenderPass.colorAttachmentCount;
+
+        // Assign the pointers in colorAttachmentsInfoPtr to items in this->mColorAttachmentsInfo
+        for (uint32_t i = 0; i < colorAttachmentCount; ++i) {
+            if (otherRenderPass.cColorAttachmentsInfoPtr[i] != nullptr) {
+                cColorAttachmentsInfoPtr[i] = &mColorAttachmentsInfo[i];
+            } else {
+                cColorAttachmentsInfoPtr[i] = nullptr;
+            }
+        }
+        colorAttachments = cColorAttachmentsInfoPtr;
+
+        if (otherRenderPass.depthStencilAttachment != nullptr) {
+            // Assign desc.depthStencilAttachment to this->depthStencilAttachmentInfo;
+            depthStencilAttachment = &cDepthStencilAttachmentInfo;
+        } else {
+            depthStencilAttachment = nullptr;
+        }
+
+        return *this;
+    }
+
+    BasicRenderPass::BasicRenderPass()
+        : width(0),
+          height(0),
+          color(nullptr),
+          colorFormat(dawn::TextureFormat::R8G8B8A8Unorm),
+          renderPassInfo({}) {
+    }
+
+    BasicRenderPass::BasicRenderPass(uint32_t texWidth,
+                                     uint32_t texHeight,
+                                     dawn::Texture colorAttachment,
+                                     dawn::TextureFormat textureFormat)
+        : width(texWidth),
+          height(texHeight),
+          color(colorAttachment),
+          colorFormat(textureFormat),
+          renderPassInfo({colorAttachment.CreateDefaultTextureView()}) {
+    }
+
     BasicRenderPass CreateBasicRenderPass(const dawn::Device& device,
                                           uint32_t width,
                                           uint32_t height) {
-        BasicRenderPass result;
-        result.width = width;
-        result.height = height;
+        DAWN_ASSERT(width > 0 && height > 0);
 
-        result.colorFormat = dawn::TextureFormat::R8G8B8A8Unorm;
+        dawn::TextureFormat kColorFormat = dawn::TextureFormat::R8G8B8A8Unorm;
+
         dawn::TextureDescriptor descriptor;
         descriptor.dimension = dawn::TextureDimension::e2D;
         descriptor.size.width = width;
@@ -141,24 +224,13 @@
         descriptor.size.depth = 1;
         descriptor.arrayLayerCount = 1;
         descriptor.sampleCount = 1;
-        descriptor.format = result.colorFormat;
+        descriptor.format = kColorFormat;
         descriptor.mipLevelCount = 1;
         descriptor.usage =
             dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::TransferSrc;
-        result.color = device.CreateTexture(&descriptor);
+        dawn::Texture color = device.CreateTexture(&descriptor);
 
-        dawn::TextureView colorView = result.color.CreateDefaultTextureView();
-        dawn::RenderPassColorAttachmentDescriptor colorAttachment;
-        colorAttachment.attachment = colorView;
-        colorAttachment.resolveTarget = nullptr;
-        colorAttachment.clearColor = {0.0f, 0.0f, 0.0f, 0.0f};
-        colorAttachment.loadOp = dawn::LoadOp::Clear;
-        colorAttachment.storeOp = dawn::StoreOp::Store;
-        result.renderPassInfo = device.CreateRenderPassDescriptorBuilder()
-                                    .SetColorAttachments(1, &colorAttachment)
-                                    .GetResult();
-
-        return result;
+        return BasicRenderPass(width, height, color, kColorFormat);
     }
 
     dawn::BufferCopyView CreateBufferCopyView(dawn::Buffer buffer,
diff --git a/src/utils/DawnHelpers.h b/src/utils/DawnHelpers.h
index 538ebe0..6a7c83d 100644
--- a/src/utils/DawnHelpers.h
+++ b/src/utils/DawnHelpers.h
@@ -17,8 +17,11 @@
 
 #include <dawn/dawncpp.h>
 
+#include <array>
 #include <initializer_list>
 
+#include "common/Constants.h"
+
 namespace utils {
 
     enum Expectation { Success, Failure };
@@ -49,12 +52,34 @@
                                                 uint32_t slice,
                                                 dawn::Origin3D origin);
 
+    struct ComboRenderPassDescriptor : public dawn::RenderPassDescriptor {
+      public:
+        ComboRenderPassDescriptor(std::initializer_list<dawn::TextureView> colorAttachmentInfo,
+                                  dawn::TextureView depthStencil = dawn::TextureView());
+        const ComboRenderPassDescriptor& operator=(
+            const ComboRenderPassDescriptor& otherRenderPass);
+
+        dawn::RenderPassColorAttachmentDescriptor* cColorAttachmentsInfoPtr[kMaxColorAttachments];
+        dawn::RenderPassDepthStencilAttachmentDescriptor cDepthStencilAttachmentInfo;
+
+      private:
+        std::array<dawn::RenderPassColorAttachmentDescriptor, kMaxColorAttachments>
+            mColorAttachmentsInfo;
+    };
+
     struct BasicRenderPass {
+      public:
+        BasicRenderPass();
+        BasicRenderPass(uint32_t width,
+                        uint32_t height,
+                        dawn::Texture color,
+                        dawn::TextureFormat texture);
+
         uint32_t width;
         uint32_t height;
         dawn::Texture color;
         dawn::TextureFormat colorFormat;
-        dawn::RenderPassDescriptor renderPassInfo;
+        utils::ComboRenderPassDescriptor renderPassInfo;
     };
     BasicRenderPass CreateBasicRenderPass(const dawn::Device& device,
                                           uint32_t width,