1 // Copyright 2021 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "tests/perf_tests/DawnPerfTest.h"
16
17 #include "utils/ComboRenderPipelineDescriptor.h"
18 #include "utils/WGPUHelpers.h"
19
20 struct SubresourceTrackingParams : AdapterTestParam {
SubresourceTrackingParamsSubresourceTrackingParams21 SubresourceTrackingParams(const AdapterTestParam& param,
22 uint32_t arrayLayerCountIn,
23 uint32_t mipLevelCountIn)
24 : AdapterTestParam(param),
25 arrayLayerCount(arrayLayerCountIn),
26 mipLevelCount(mipLevelCountIn) {
27 }
28 uint32_t arrayLayerCount;
29 uint32_t mipLevelCount;
30 };
31
operator <<(std::ostream & ostream,const SubresourceTrackingParams & param)32 std::ostream& operator<<(std::ostream& ostream, const SubresourceTrackingParams& param) {
33 ostream << static_cast<const AdapterTestParam&>(param);
34 ostream << "_arrayLayer_" << param.arrayLayerCount;
35 ostream << "_mipLevel_" << param.mipLevelCount;
36 return ostream;
37 }
38
39 // Test the performance of Subresource usage and barrier tracking on a case that would generally be
40 // difficult. It uses a 2D array texture with mipmaps and updates one of the layers with data from
41 // another texture, then generates mipmaps for that layer. It is difficult because it requires
42 // tracking the state of individual subresources in the middle of the subresources of that texture.
43 class SubresourceTrackingPerf : public DawnPerfTestWithParams<SubresourceTrackingParams> {
44 public:
45 static constexpr unsigned int kNumIterations = 50;
46
SubresourceTrackingPerf()47 SubresourceTrackingPerf() : DawnPerfTestWithParams(kNumIterations, 1) {
48 }
49 ~SubresourceTrackingPerf() override = default;
50
SetUp()51 void SetUp() override {
52 DawnPerfTestWithParams<SubresourceTrackingParams>::SetUp();
53 const SubresourceTrackingParams& params = GetParam();
54
55 wgpu::TextureDescriptor materialDesc;
56 materialDesc.dimension = wgpu::TextureDimension::e2D;
57 materialDesc.size = {1u << (params.mipLevelCount - 1), 1u << (params.mipLevelCount - 1),
58 params.arrayLayerCount};
59 materialDesc.mipLevelCount = params.mipLevelCount;
60 materialDesc.usage = wgpu::TextureUsage::TextureBinding |
61 wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopyDst;
62 materialDesc.format = wgpu::TextureFormat::RGBA8Unorm;
63 mMaterials = device.CreateTexture(&materialDesc);
64
65 wgpu::TextureDescriptor uploadTexDesc = materialDesc;
66 uploadTexDesc.size.depthOrArrayLayers = 1;
67 uploadTexDesc.mipLevelCount = 1;
68 uploadTexDesc.usage = wgpu::TextureUsage::CopySrc;
69 mUploadTexture = device.CreateTexture(&uploadTexDesc);
70
71 utils::ComboRenderPipelineDescriptor pipelineDesc;
72 pipelineDesc.vertex.module = utils::CreateShaderModule(device, R"(
73 [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
74 return vec4<f32>(1.0, 0.0, 0.0, 1.0);
75 }
76 )");
77 pipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
78 [[group(0), binding(0)]] var materials : texture_2d<f32>;
79 [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
80 let foo : vec2<i32> = textureDimensions(materials);
81 return vec4<f32>(1.0, 0.0, 0.0, 1.0);
82 }
83 )");
84 mPipeline = device.CreateRenderPipeline(&pipelineDesc);
85 }
86
87 private:
Step()88 void Step() override {
89 const SubresourceTrackingParams& params = GetParam();
90
91 uint32_t layerUploaded = params.arrayLayerCount / 2;
92
93 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
94
95 // Copy into the layer of the material array.
96 {
97 wgpu::ImageCopyTexture sourceView;
98 sourceView.texture = mUploadTexture;
99
100 wgpu::ImageCopyTexture destView;
101 destView.texture = mMaterials;
102 destView.origin.z = layerUploaded;
103
104 wgpu::Extent3D copySize = {1u << (params.mipLevelCount - 1),
105 1u << (params.mipLevelCount - 1), 1};
106
107 encoder.CopyTextureToTexture(&sourceView, &destView, ©Size);
108 }
109
110 // Fake commands that would be used to create the mip levels.
111 for (uint32_t level = 1; level < params.mipLevelCount; level++) {
112 wgpu::TextureViewDescriptor rtViewDesc;
113 rtViewDesc.dimension = wgpu::TextureViewDimension::e2D;
114 rtViewDesc.baseMipLevel = level;
115 rtViewDesc.mipLevelCount = 1;
116 rtViewDesc.baseArrayLayer = layerUploaded;
117 rtViewDesc.arrayLayerCount = 1;
118 wgpu::TextureView rtView = mMaterials.CreateView(&rtViewDesc);
119
120 wgpu::TextureViewDescriptor sampleViewDesc = rtViewDesc;
121 sampleViewDesc.baseMipLevel = level - 1;
122 wgpu::TextureView sampleView = mMaterials.CreateView(&sampleViewDesc);
123
124 wgpu::BindGroup bindgroup =
125 utils::MakeBindGroup(device, mPipeline.GetBindGroupLayout(0), {{0, sampleView}});
126
127 utils::ComboRenderPassDescriptor renderPass({rtView});
128 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
129 pass.SetPipeline(mPipeline);
130 pass.SetBindGroup(0, bindgroup);
131 pass.Draw(3);
132 pass.EndPass();
133 }
134
135 wgpu::CommandBuffer commands = encoder.Finish();
136 queue.Submit(1, &commands);
137 }
138
139 wgpu::Texture mUploadTexture;
140 wgpu::Texture mMaterials;
141 wgpu::RenderPipeline mPipeline;
142 };
143
TEST_P(SubresourceTrackingPerf,Run)144 TEST_P(SubresourceTrackingPerf, Run) {
145 RunTest();
146 }
147
148 DAWN_INSTANTIATE_TEST_P(SubresourceTrackingPerf,
149 {D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()},
150 {1, 4, 16, 256},
151 {2, 3, 8});
152