D3D12: Remove RenderPassDescriptorD3D12

This patch removes RenderPassDescriptorD3D12 completely and moves the
creation of RTVs and DSVs to CommandBufferD3D12::RecordCommands(), where
we allocate all RTVs and DSVs used in the current command buffer in one
RTV heap and one DSV heap. Note that the method to allocate RTVs and
DSVs are too simple in this patch, and we will optimize it later.

This patch also adds a test to make sure Dawn works correctly when we
use two different render passes in one command buffer.

This patch is one of the preparations on completely removing
RenderPassDescriptorBuilder from Dawn.

BUG=dawn:6

Change-Id: I02e30c007fb8668a7474a3caf7a858782d0c92df
Reviewed-on: https://dawn-review.googlesource.com/c/4520
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Jiawei Shao 2019-02-15 10:55:08 +00:00 committed by Commit Bot service account
parent 108bcbd5c9
commit c8b067d2df
8 changed files with 238 additions and 147 deletions

View File

@ -537,8 +537,6 @@ source_set("libdawn_native_sources") {
"src/dawn_native/d3d12/PlatformFunctions.h",
"src/dawn_native/d3d12/QueueD3D12.cpp",
"src/dawn_native/d3d12/QueueD3D12.h",
"src/dawn_native/d3d12/RenderPassDescriptorD3D12.cpp",
"src/dawn_native/d3d12/RenderPassDescriptorD3D12.h",
"src/dawn_native/d3d12/RenderPipelineD3D12.cpp",
"src/dawn_native/d3d12/RenderPipelineD3D12.h",
"src/dawn_native/d3d12/ResourceAllocator.cpp",
@ -1011,6 +1009,7 @@ test("dawn_end2end_tests") {
"src/tests/end2end/PrimitiveTopologyTests.cpp",
"src/tests/end2end/PushConstantTests.cpp",
"src/tests/end2end/RenderPassLoadOpTests.cpp",
"src/tests/end2end/RenderPassTests.cpp",
"src/tests/end2end/SamplerTests.cpp",
"src/tests/end2end/ScissorTests.cpp",
"src/tests/end2end/TextureViewTests.cpp",

View File

@ -24,7 +24,6 @@
#include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/InputStateD3D12.h"
#include "dawn_native/d3d12/PipelineLayoutD3D12.h"
#include "dawn_native/d3d12/RenderPassDescriptorD3D12.h"
#include "dawn_native/d3d12/RenderPipelineD3D12.h"
#include "dawn_native/d3d12/ResourceAllocator.h"
#include "dawn_native/d3d12/SamplerD3D12.h"
@ -156,10 +155,94 @@ namespace dawn_native { namespace d3d12 {
}
};
struct OMSetRenderTargetArgs {
unsigned int numRTVs = 0;
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, kMaxColorAttachments> RTVs = {};
D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
};
class RenderPassDescriptorHeapTracker {
public:
RenderPassDescriptorHeapTracker(Device* device) : mDevice(device) {
}
// This function must only be called before calling AllocateRTVAndDSVHeaps().
void TrackRenderPass(const RenderPassDescriptor* renderPass) {
DAWN_ASSERT(mRTVHeap.Get() == nullptr && mDSVHeap.Get() == nullptr);
mNumRTVs += static_cast<uint32_t>(renderPass->GetColorAttachmentMask().count());
if (renderPass->HasDepthStencilAttachment()) {
++mNumDSVs;
}
}
void AllocateRTVAndDSVHeaps() {
// This function should only be called once.
DAWN_ASSERT(mRTVHeap.Get() == nullptr && mDSVHeap.Get() == nullptr);
DescriptorHeapAllocator* allocator = mDevice->GetDescriptorHeapAllocator();
if (mNumRTVs > 0) {
mRTVHeap = allocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, mNumRTVs);
}
if (mNumDSVs > 0) {
mDSVHeap = allocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, mNumDSVs);
}
}
// TODO(jiawei.shao@intel.com): use hash map <RenderPass, OMSetRenderTargetArgs> as cache to
// avoid redundant RTV and DSV memory allocations.
OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs(RenderPassDescriptor* renderPass) {
OMSetRenderTargetArgs args = {};
unsigned int rtvIndex = 0;
uint32_t rtvCount = static_cast<uint32_t>(renderPass->GetColorAttachmentMask().count());
DAWN_ASSERT(mAllocatedRTVs + rtvCount <= mNumRTVs);
for (uint32_t i : IterateBitSet(renderPass->GetColorAttachmentMask())) {
TextureView* view = ToBackend(renderPass->GetColorAttachment(i).view).Get();
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = mRTVHeap.GetCPUHandle(mAllocatedRTVs);
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = view->GetRTVDescriptor();
mDevice->GetD3D12Device()->CreateRenderTargetView(
ToBackend(view->GetTexture())->GetD3D12Resource(), &rtvDesc, rtvHandle);
args.RTVs[i] = rtvHandle;
++rtvIndex;
++mAllocatedRTVs;
}
args.numRTVs = rtvIndex;
if (renderPass->HasDepthStencilAttachment()) {
DAWN_ASSERT(mAllocatedDSVs < mNumDSVs);
TextureView* view = ToBackend(renderPass->GetDepthStencilAttachment().view).Get();
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = mDSVHeap.GetCPUHandle(mAllocatedDSVs);
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = view->GetDSVDescriptor();
mDevice->GetD3D12Device()->CreateDepthStencilView(
ToBackend(view->GetTexture())->GetD3D12Resource(), &dsvDesc, dsvHandle);
args.dsv = dsvHandle;
++mAllocatedDSVs;
}
return args;
}
bool IsHeapAllocationCompleted() const {
return mNumRTVs == mAllocatedRTVs && mNumDSVs == mAllocatedDSVs;
}
private:
Device* mDevice;
DescriptorHeapHandle mRTVHeap = {};
DescriptorHeapHandle mDSVHeap = {};
uint32_t mNumRTVs = 0;
uint32_t mNumDSVs = 0;
uint32_t mAllocatedRTVs = 0;
uint32_t mAllocatedDSVs = 0;
};
namespace {
void AllocateAndSetDescriptorHeaps(Device* device,
BindGroupStateTracker* bindingTracker,
RenderPassDescriptorHeapTracker* renderPassTracker,
CommandIterator* commands,
int indexInSubmit) {
auto* descriptorHeapAllocator = device->GetDescriptorHeapAllocator();
@ -198,6 +281,10 @@ namespace dawn_native { namespace d3d12 {
BindGroup* group = ToBackend(cmd->group.Get());
bindingTracker->TrackSetBindGroup(group, cmd->index, indexInSubmit);
} break;
case Command::BeginRenderPass: {
BeginRenderPassCmd* cmd = commands->NextCommand<BeginRenderPassCmd>();
renderPassTracker->TrackRenderPass(cmd->info.Get());
} break;
default:
SkipCommand(commands, type);
}
@ -206,6 +293,8 @@ namespace dawn_native { namespace d3d12 {
commands->Reset();
}
renderPassTracker->AllocateRTVAndDSVHeaps();
if (bindingTracker->cbvSrvUavDescriptorIndex > 0) {
// Allocate a GPU-visible heap and copy from the CPU-only heap to the GPU-visible
// heap
@ -245,13 +334,15 @@ namespace dawn_native { namespace d3d12 {
uint32_t indexInSubmit) {
Device* device = ToBackend(GetDevice());
BindGroupStateTracker bindingTracker(device);
RenderPassDescriptorHeapTracker renderPassTracker(device);
// Precompute the allocation of bindgroups in descriptor heaps
// TODO(cwallez@chromium.org): Iterating over all the commands here is inefficient. We
// should have a system where commands and descriptors are recorded in parallel then the
// heaps set using a small CommandList inserted just before the main CommandList.
{
AllocateAndSetDescriptorHeaps(device, &bindingTracker, &mCommands, indexInSubmit);
AllocateAndSetDescriptorHeaps(device, &bindingTracker, &renderPassTracker, &mCommands,
indexInSubmit);
bindingTracker.Reset();
ID3D12DescriptorHeap* descriptorHeaps[2] = {
@ -301,7 +392,7 @@ namespace dawn_native { namespace d3d12 {
TransitionForPass(commandList, passResourceUsages[nextPassNumber]);
bindingTracker.SetInComputePass(false);
RecordRenderPass(commandList, &bindingTracker,
RecordRenderPass(commandList, &bindingTracker, &renderPassTracker,
ToBackend(beginRenderPassCmd->info.Get()));
nextPassNumber++;
@ -418,6 +509,8 @@ namespace dawn_native { namespace d3d12 {
default: { UNREACHABLE(); } break;
}
}
DAWN_ASSERT(renderPassTracker.IsHeapAllocationCompleted());
}
void CommandBuffer::FlushSetVertexBuffers(ComPtr<ID3D12GraphicsCommandList> commandList,
@ -503,7 +596,10 @@ namespace dawn_native { namespace d3d12 {
void CommandBuffer::RecordRenderPass(ComPtr<ID3D12GraphicsCommandList> commandList,
BindGroupStateTracker* bindingTracker,
RenderPassDescriptorHeapTracker* renderPassTracker,
RenderPassDescriptor* renderPass) {
OMSetRenderTargetArgs args = renderPassTracker->GetSubpassOMSetRenderTargetArgs(renderPass);
// Clear framebuffer attachments as needed and transition to render target
{
for (uint32_t i : IterateBitSet(renderPass->GetColorAttachmentMask())) {
@ -511,7 +607,7 @@ namespace dawn_native { namespace d3d12 {
// Load op - color
if (attachmentInfo.loadOp == dawn::LoadOp::Clear) {
D3D12_CPU_DESCRIPTOR_HANDLE handle = renderPass->GetRTVDescriptor(i);
D3D12_CPU_DESCRIPTOR_HANDLE handle = args.RTVs[i];
commandList->ClearRenderTargetView(handle, attachmentInfo.clearColor.data(), 0,
nullptr);
}
@ -536,7 +632,7 @@ namespace dawn_native { namespace d3d12 {
}
if (clearFlags) {
auto handle = renderPass->GetDSVDescriptor();
D3D12_CPU_DESCRIPTOR_HANDLE handle = args.dsv;
// TODO(kainino@chromium.org): investigate: should the Dawn clear
// stencil type be uint8_t?
uint8_t clearStencil = static_cast<uint8_t>(attachmentInfo.clearStencil);
@ -548,8 +644,6 @@ namespace dawn_native { namespace d3d12 {
// Set up render targets
{
RenderPassDescriptor::OMSetRenderTargetArgs args =
renderPass->GetSubpassOMSetRenderTargetArgs();
if (args.dsv.ptr) {
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE, &args.dsv);
} else {

View File

@ -18,13 +18,14 @@
#include "dawn_native/CommandAllocator.h"
#include "dawn_native/CommandBuffer.h"
#include "dawn_native/d3d12/Forward.h"
#include "dawn_native/d3d12/InputStateD3D12.h"
#include "dawn_native/d3d12/d3d12_platform.h"
namespace dawn_native { namespace d3d12 {
class Device;
class RenderPassDescriptor;
class RenderPassDescriptorHeapTracker;
struct BindGroupStateTracker;
@ -54,6 +55,7 @@ namespace dawn_native { namespace d3d12 {
BindGroupStateTracker* bindingTracker);
void RecordRenderPass(ComPtr<ID3D12GraphicsCommandList> commandList,
BindGroupStateTracker* bindingTracker,
RenderPassDescriptorHeapTracker* renderPassTracker,
RenderPassDescriptor* renderPass);
CommandIterator mCommands;

View File

@ -17,6 +17,7 @@
#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"
@ -30,7 +31,6 @@
#include "dawn_native/d3d12/PipelineLayoutD3D12.h"
#include "dawn_native/d3d12/PlatformFunctions.h"
#include "dawn_native/d3d12/QueueD3D12.h"
#include "dawn_native/d3d12/RenderPassDescriptorD3D12.h"
#include "dawn_native/d3d12/RenderPipelineD3D12.h"
#include "dawn_native/d3d12/ResourceAllocator.h"
#include "dawn_native/d3d12/SamplerD3D12.h"

View File

@ -29,7 +29,7 @@ namespace dawn_native { namespace d3d12 {
class InputState;
class PipelineLayout;
class Queue;
class RenderPassDescriptor;
using RenderPassDescriptor = RenderPassDescriptorBase;
class RenderPipeline;
class Sampler;
class ShaderModule;

View File

@ -1,84 +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/d3d12/RenderPassDescriptorD3D12.h"
#include "common/BitSetIterator.h"
#include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/TextureD3D12.h"
namespace dawn_native { namespace d3d12 {
RenderPassDescriptor::RenderPassDescriptor(RenderPassDescriptorBuilder* builder)
: RenderPassDescriptorBase(builder) {
Device* device = ToBackend(GetDevice());
// Get and fill an RTV heap with the color attachments
uint32_t colorAttachmentCount = static_cast<uint32_t>(GetColorAttachmentMask().count());
if (colorAttachmentCount != 0) {
mRtvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
D3D12_DESCRIPTOR_HEAP_TYPE_RTV, colorAttachmentCount);
for (uint32_t i : IterateBitSet(GetColorAttachmentMask())) {
TextureView* view = ToBackend(GetColorAttachment(i).view.Get());
ComPtr<ID3D12Resource> resource = ToBackend(view->GetTexture())->GetD3D12Resource();
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = mRtvHeap.GetCPUHandle(i);
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = view->GetRTVDescriptor();
device->GetD3D12Device()->CreateRenderTargetView(resource.Get(), &rtvDesc,
rtvHandle);
}
}
// Get and fill a DSV heap with the depth stencil attachment
if (HasDepthStencilAttachment()) {
mDsvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1);
TextureView* view = ToBackend(GetDepthStencilAttachment().view.Get());
ComPtr<ID3D12Resource> resource = ToBackend(view->GetTexture())->GetD3D12Resource();
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = mDsvHeap.GetCPUHandle(0);
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = view->GetDSVDescriptor();
device->GetD3D12Device()->CreateDepthStencilView(resource.Get(), &dsvDesc, dsvHandle);
}
}
RenderPassDescriptor::OMSetRenderTargetArgs
RenderPassDescriptor::GetSubpassOMSetRenderTargetArgs() {
OMSetRenderTargetArgs args = {};
unsigned int rtvIndex = 0;
for (uint32_t i : IterateBitSet(GetColorAttachmentMask())) {
args.RTVs[rtvIndex] = GetRTVDescriptor(i);
rtvIndex++;
}
args.numRTVs = rtvIndex;
if (HasDepthStencilAttachment()) {
args.dsv = GetDSVDescriptor();
}
return args;
}
D3D12_CPU_DESCRIPTOR_HANDLE RenderPassDescriptor::GetRTVDescriptor(uint32_t attachmentSlot) {
return mRtvHeap.GetCPUHandle(attachmentSlot);
}
D3D12_CPU_DESCRIPTOR_HANDLE RenderPassDescriptor::GetDSVDescriptor() {
return mDsvHeap.GetCPUHandle(0);
}
}} // namespace dawn_native::d3d12

View File

@ -1,51 +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_D3D12_RENDERPASSDESCRIPTORD3D12_H_
#define DAWNNATIVE_D3D12_RENDERPASSDESCRIPTORD3D12_H_
#include "dawn_native/RenderPassDescriptor.h"
#include "common/Constants.h"
#include "dawn_native/d3d12/DescriptorHeapAllocator.h"
#include "dawn_native/d3d12/d3d12_platform.h"
#include <array>
#include <vector>
namespace dawn_native { namespace d3d12 {
class Device;
class RenderPassDescriptor : public RenderPassDescriptorBase {
public:
struct OMSetRenderTargetArgs {
unsigned int numRTVs = 0;
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, kMaxColorAttachments> RTVs = {};
D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
};
RenderPassDescriptor(RenderPassDescriptorBuilder* builder);
OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs();
D3D12_CPU_DESCRIPTOR_HANDLE GetRTVDescriptor(uint32_t attachmentSlot);
D3D12_CPU_DESCRIPTOR_HANDLE GetDSVDescriptor();
private:
DescriptorHeapHandle mRtvHeap = {};
DescriptorHeapHandle mDsvHeap = {};
};
}} // namespace dawn_native::d3d12
#endif // DAWNNATIVE_D3D12_RENDERPASSDESCRIPTORD3D12_H_

View File

@ -0,0 +1,131 @@
// Copyright 2019 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 "tests/DawnTest.h"
#include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/DawnHelpers.h"
constexpr uint32_t kRTSize = 16;
constexpr dawn::TextureFormat kFormat = dawn::TextureFormat::R8G8B8A8Unorm;
class RenderPassTest : public DawnTest {
protected:
void SetUp() override {
DawnTest::SetUp();
// Shaders to draw a bottom-left triangle in blue.
dawn::ShaderModule vsModule =
utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, R"(
#version 450
void main() {
const vec2 pos[3] = vec2[3](
vec2(-1.f, -1.f), vec2(1.f, 1.f), vec2(-1.f, 1.f));
gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f);
})");
dawn::ShaderModule fsModule =
utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
#version 450
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = vec4(0.0, 0.0, 1.0, 1.0);
})");
utils::ComboRenderPipelineDescriptor descriptor(device);
descriptor.cVertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule;
descriptor.primitiveTopology = dawn::PrimitiveTopology::TriangleStrip;
descriptor.indexFormat = dawn::IndexFormat::Uint32;
descriptor.cColorStates[0].format = kFormat;
pipeline = device.CreateRenderPipeline(&descriptor);
}
dawn::Texture CreateDefault2DTexture() {
dawn::TextureDescriptor descriptor;
descriptor.dimension = dawn::TextureDimension::e2D;
descriptor.size.width = kRTSize;
descriptor.size.height = kRTSize;
descriptor.size.depth = 1;
descriptor.arraySize = 1;
descriptor.sampleCount = 1;
descriptor.format = kFormat;
descriptor.levelCount = 1;
descriptor.usage =
dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::TransferSrc;
return device.CreateTexture(&descriptor);
}
dawn::RenderPipeline pipeline;
};
// Test using two different render passes in one commandBuffer works correctly.
TEST_P(RenderPassTest, TwoRenderPassesInOneCommandBuffer) {
constexpr RGBA8 kRed(255, 0, 0, 255);
constexpr RGBA8 kGreen(0, 255, 0, 255);
constexpr RGBA8 kBlue(0, 0, 255, 255);
dawn::Texture renderTarget1 = CreateDefault2DTexture();
dawn::Texture renderTarget2 = CreateDefault2DTexture();
dawn::CommandBufferBuilder commandBufferBuilder = device.CreateCommandBufferBuilder();
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 };
colorAttachment.attachment = renderTarget1.CreateDefaultTextureView();
dawn::RenderPassDescriptor renderPass = device.CreateRenderPassDescriptorBuilder()
.SetColorAttachments(1, &colorAttachment)
.GetResult();
dawn::RenderPassEncoder pass = commandBufferBuilder.BeginRenderPass(renderPass);
pass.SetPipeline(pipeline);
pass.Draw(3, 1, 0, 0);
pass.EndPass();
}
{
// 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();
dawn::RenderPassEncoder pass = commandBufferBuilder.BeginRenderPass(renderPass);
pass.SetPipeline(pipeline);
pass.Draw(3, 1, 0, 0);
pass.EndPass();
}
dawn::CommandBuffer commands = commandBufferBuilder.GetResult();
queue.Submit(1, &commands);
EXPECT_PIXEL_RGBA8_EQ(kBlue, renderTarget1, 1, kRTSize - 1);
EXPECT_PIXEL_RGBA8_EQ(kRed, renderTarget1, kRTSize - 1, 1);
EXPECT_PIXEL_RGBA8_EQ(kBlue, renderTarget2, 1, kRTSize - 1);
EXPECT_PIXEL_RGBA8_EQ(kGreen, renderTarget2, kRTSize - 1, 1);
}
DAWN_INSTANTIATE_TEST(RenderPassTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)