Add the SubresourceTrackingPerf perf test.

This is a performance test in preparation of using SubresourceStorage
in dawn_native. On the Vulkan backend with Swiftshader it shows that
SubresourceStorage will bring a small perf regression for simple cases
(<= 10%) but it that complex cases are improved significantly (up to
twice faster).

Also renames a variable to follow the mMemberName convention.

Bug: dawn:441

Change-Id: I3fec80cba39b7d2aaba08fc8fbd8ea913ed5501c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/37041
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Auto-Submit: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
diff --git a/src/tests/BUILD.gn b/src/tests/BUILD.gn
index 1c78506..5a3e310 100644
--- a/src/tests/BUILD.gn
+++ b/src/tests/BUILD.gn
@@ -496,6 +496,7 @@
     "perf_tests/DawnPerfTestPlatform.cpp",
     "perf_tests/DawnPerfTestPlatform.h",
     "perf_tests/DrawCallPerf.cpp",
+    "perf_tests/SubresourceTrackingPerf.cpp",
   ]
 
   libs = []
diff --git a/src/tests/perf_tests/DawnPerfTest.cpp b/src/tests/perf_tests/DawnPerfTest.cpp
index 58a0cbe6..1ae3971 100644
--- a/src/tests/perf_tests/DawnPerfTest.cpp
+++ b/src/tests/perf_tests/DawnPerfTest.cpp
@@ -234,7 +234,7 @@
     dawn_platform::Platform* platform = gTestEnv->GetPlatform();
 
     mNumStepsPerformed = 0;
-    cpuTime = 0;
+    mCpuTime = 0;
     mRunning = true;
 
     wgpu::FenceDescriptor desc = {};
@@ -252,7 +252,7 @@
         TRACE_EVENT0(platform, General, "Step");
         double stepStart = mTimer->GetElapsedTime();
         Step();
-        cpuTime += mTimer->GetElapsedTime() - stepStart;
+        mCpuTime += mTimer->GetElapsedTime() - stepStart;
 
         mTest->queue.Signal(fence, ++signaledFenceValue);
 
@@ -340,7 +340,7 @@
     }
 
     PrintPerIterationResultFromSeconds("wall_time", mTimer->GetElapsedTime(), true);
-    PrintPerIterationResultFromSeconds("cpu_time", cpuTime, true);
+    PrintPerIterationResultFromSeconds("cpu_time", mCpuTime, true);
     PrintPerIterationResultFromSeconds("validation_time", totalValidationTime, true);
     PrintPerIterationResultFromSeconds("recording_time", totalRecordingTime, true);
 
diff --git a/src/tests/perf_tests/DawnPerfTest.h b/src/tests/perf_tests/DawnPerfTest.h
index d32e64e..3c1e7a9 100644
--- a/src/tests/perf_tests/DawnPerfTest.h
+++ b/src/tests/perf_tests/DawnPerfTest.h
@@ -104,7 +104,7 @@
     const unsigned int mMaxStepsInFlight;
     unsigned int mStepsToRun = 0;
     unsigned int mNumStepsPerformed = 0;
-    double cpuTime;
+    double mCpuTime;
     std::unique_ptr<utils::Timer> mTimer;
 };
 
diff --git a/src/tests/perf_tests/SubresourceTrackingPerf.cpp b/src/tests/perf_tests/SubresourceTrackingPerf.cpp
new file mode 100644
index 0000000..8be7e4b
--- /dev/null
+++ b/src/tests/perf_tests/SubresourceTrackingPerf.cpp
@@ -0,0 +1,154 @@
+// Copyright 2021 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/perf_tests/DawnPerfTest.h"
+
+#include "tests/ParamGenerator.h"
+#include "utils/ComboRenderPipelineDescriptor.h"
+#include "utils/WGPUHelpers.h"
+
+struct SubresourceTrackingParams : AdapterTestParam {
+    SubresourceTrackingParams(const AdapterTestParam& param,
+                              uint32_t arrayLayerCountIn,
+                              uint32_t mipLevelCountIn)
+        : AdapterTestParam(param),
+          arrayLayerCount(arrayLayerCountIn),
+          mipLevelCount(mipLevelCountIn) {
+    }
+    uint32_t arrayLayerCount;
+    uint32_t mipLevelCount;
+};
+
+std::ostream& operator<<(std::ostream& ostream, const SubresourceTrackingParams& param) {
+    ostream << static_cast<const AdapterTestParam&>(param);
+    ostream << "_arrayLayer_" << param.arrayLayerCount;
+    ostream << "_mipLevel_" << param.mipLevelCount;
+    return ostream;
+}
+
+// Test the performance of Subresource usage and barrier tracking on a case that would generally be
+// difficult. It uses a 2D array texture with mipmaps and updates one of the layers with data from
+// another texture, then generates mipmaps for that layer. It is difficult because it requires
+// tracking the state of individual subresources in the middle of the subresources of that texture.
+class SubresourceTrackingPerf : public DawnPerfTestWithParams<SubresourceTrackingParams> {
+  public:
+    static constexpr unsigned int kNumIterations = 50;
+
+    SubresourceTrackingPerf() : DawnPerfTestWithParams(kNumIterations, 1) {
+    }
+    ~SubresourceTrackingPerf() override = default;
+
+    void SetUp() override {
+        DawnPerfTestWithParams<SubresourceTrackingParams>::SetUp();
+        const SubresourceTrackingParams& params = GetParam();
+
+        wgpu::TextureDescriptor materialDesc;
+        materialDesc.dimension = wgpu::TextureDimension::e2D;
+        materialDesc.size = {1u << (params.mipLevelCount - 1), 1u << (params.mipLevelCount - 1),
+                             params.arrayLayerCount};
+        materialDesc.mipLevelCount = params.mipLevelCount;
+        materialDesc.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::RenderAttachment |
+                             wgpu::TextureUsage::CopyDst;
+        materialDesc.format = wgpu::TextureFormat::RGBA8Unorm;
+        mMaterials = device.CreateTexture(&materialDesc);
+
+        wgpu::TextureDescriptor uploadTexDesc = materialDesc;
+        uploadTexDesc.size.depth = 1;
+        uploadTexDesc.mipLevelCount = 1;
+        uploadTexDesc.usage = wgpu::TextureUsage::CopySrc;
+        mUploadTexture = device.CreateTexture(&uploadTexDesc);
+
+        utils::ComboRenderPipelineDescriptor pipelineDesc(device);
+        pipelineDesc.vertexStage.module = utils::CreateShaderModuleFromWGSL(device, R"(
+            [[builtin(position)]] var<out> Position : vec4<f32>;
+            [[stage(vertex)]] fn main() -> void {
+                Position = vec4<f32>(1.0, 0.0, 0.0, 1.0);
+            }
+        )");
+        pipelineDesc.cFragmentStage.module = utils::CreateShaderModuleFromWGSL(device, R"(
+            [[location(0)]] var<out> FragColor : vec4<f32>;
+            [[set(0), binding(0)]] var<uniform_constant> materials : texture_sampled_2d<f32>;
+            [[stage(fragment)]] fn main() -> void {
+                FragColor = vec4<f32>(1.0, 0.0, 0.0, 1.0);
+            }
+        )");
+        mPipeline = device.CreateRenderPipeline(&pipelineDesc);
+    }
+
+  private:
+    void Step() override {
+        const SubresourceTrackingParams& params = GetParam();
+
+        uint32_t layerUploaded = params.arrayLayerCount / 2;
+
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+
+        // Copy into the layer of the material array.
+        {
+            wgpu::TextureCopyView sourceView;
+            sourceView.texture = mUploadTexture;
+
+            wgpu::TextureCopyView destView;
+            destView.texture = mMaterials;
+            destView.origin.z = layerUploaded;
+
+            wgpu::Extent3D copySize = {1u << (params.mipLevelCount - 1),
+                                       1u << (params.mipLevelCount - 1), 1};
+
+            encoder.CopyTextureToTexture(&sourceView, &destView, &copySize);
+        }
+
+        // Fake commands that would be used to create the mip levels.
+        for (uint32_t level = 1; level < params.mipLevelCount; level++) {
+            wgpu::TextureViewDescriptor rtViewDesc;
+            rtViewDesc.dimension = wgpu::TextureViewDimension::e2D;
+            rtViewDesc.baseMipLevel = level;
+            rtViewDesc.mipLevelCount = 1;
+            rtViewDesc.baseArrayLayer = layerUploaded;
+            rtViewDesc.arrayLayerCount = 1;
+            wgpu::TextureView rtView = mMaterials.CreateView(&rtViewDesc);
+
+            wgpu::TextureViewDescriptor sampleViewDesc = rtViewDesc;
+            sampleViewDesc.baseMipLevel = level - 1;
+            wgpu::TextureView sampleView = mMaterials.CreateView(&sampleViewDesc);
+
+            wgpu::BindGroup bindgroup =
+                utils::MakeBindGroup(device, mPipeline.GetBindGroupLayout(0), {{0, sampleView}});
+
+            utils::ComboRenderPassDescriptor renderPass({rtView});
+            wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
+            pass.SetPipeline(mPipeline);
+            pass.SetBindGroup(0, bindgroup);
+            pass.Draw(3);
+            pass.EndPass();
+        }
+
+        wgpu::CommandBuffer commands = encoder.Finish();
+        queue.Submit(1, &commands);
+    }
+
+    wgpu::Texture mUploadTexture;
+    wgpu::Texture mMaterials;
+    wgpu::RenderPipeline mPipeline;
+};
+
+TEST_P(SubresourceTrackingPerf, Run) {
+    RunTest();
+}
+
+DAWN_INSTANTIATE_PERF_TEST_SUITE_P(SubresourceTrackingPerf,
+                                   {D3D12Backend(), MetalBackend(), OpenGLBackend(),
+                                    VulkanBackend()},
+                                   {1, 4, 16, 256},
+                                   {2, 3, 8});