1 // Copyright 2020 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/DawnTest.h"
16
17 #include "utils/ComboRenderPipelineDescriptor.h"
18 #include "utils/WGPUHelpers.h"
19
20 class TextureSubresourceTest : public DawnTest {
21 public:
22 static constexpr uint32_t kSize = 4u;
23 static constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA8Unorm;
24
CreateTexture(uint32_t mipLevelCount,uint32_t arrayLayerCount,wgpu::TextureUsage usage)25 wgpu::Texture CreateTexture(uint32_t mipLevelCount,
26 uint32_t arrayLayerCount,
27 wgpu::TextureUsage usage) {
28 wgpu::TextureDescriptor texDesc;
29 texDesc.dimension = wgpu::TextureDimension::e2D;
30 texDesc.size = {kSize, kSize, arrayLayerCount};
31 texDesc.sampleCount = 1;
32 texDesc.mipLevelCount = mipLevelCount;
33 texDesc.usage = usage;
34 texDesc.format = kFormat;
35 return device.CreateTexture(&texDesc);
36 }
37
CreateTextureView(wgpu::Texture texture,uint32_t baseMipLevel,uint32_t baseArrayLayer)38 wgpu::TextureView CreateTextureView(wgpu::Texture texture,
39 uint32_t baseMipLevel,
40 uint32_t baseArrayLayer) {
41 wgpu::TextureViewDescriptor viewDesc;
42 viewDesc.format = kFormat;
43 viewDesc.baseArrayLayer = baseArrayLayer;
44 viewDesc.arrayLayerCount = 1;
45 viewDesc.baseMipLevel = baseMipLevel;
46 viewDesc.mipLevelCount = 1;
47 viewDesc.dimension = wgpu::TextureViewDimension::e2D;
48 return texture.CreateView(&viewDesc);
49 }
50
DrawTriangle(const wgpu::TextureView & view)51 void DrawTriangle(const wgpu::TextureView& view) {
52 wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
53 [[stage(vertex)]]
54 fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
55 var pos = array<vec2<f32>, 3>(
56 vec2<f32>(-1.0, 1.0),
57 vec2<f32>(-1.0, -1.0),
58 vec2<f32>( 1.0, -1.0));
59
60 return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
61 })");
62
63 wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
64 [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
65 return vec4<f32>(1.0, 0.0, 0.0, 1.0);
66 })");
67
68 utils::ComboRenderPipelineDescriptor descriptor;
69 descriptor.vertex.module = vsModule;
70 descriptor.cFragment.module = fsModule;
71 descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
72 descriptor.cTargets[0].format = kFormat;
73
74 wgpu::RenderPipeline rp = device.CreateRenderPipeline(&descriptor);
75
76 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
77
78 utils::ComboRenderPassDescriptor renderPassDesc({view});
79 renderPassDesc.cColorAttachments[0].clearColor = {0.0f, 0.0f, 0.0f, 1.0f};
80 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
81 pass.SetPipeline(rp);
82 pass.Draw(3);
83 pass.EndPass();
84 wgpu::CommandBuffer commands = encoder.Finish();
85 queue.Submit(1, &commands);
86 }
87
SampleAndDraw(const wgpu::TextureView & samplerView,const wgpu::TextureView & renderView)88 void SampleAndDraw(const wgpu::TextureView& samplerView, const wgpu::TextureView& renderView) {
89 wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
90 [[stage(vertex)]]
91 fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
92 var pos = array<vec2<f32>, 6>(
93 vec2<f32>(-1.0, -1.0),
94 vec2<f32>( 1.0, 1.0),
95 vec2<f32>(-1.0, 1.0),
96 vec2<f32>(-1.0, -1.0),
97 vec2<f32>( 1.0, -1.0),
98 vec2<f32>( 1.0, 1.0));
99
100 return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
101 })");
102
103 wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
104 [[group(0), binding(0)]] var samp : sampler;
105 [[group(0), binding(1)]] var tex : texture_2d<f32>;
106
107 [[stage(fragment)]]
108 fn main([[builtin(position)]] FragCoord : vec4<f32>) -> [[location(0)]] vec4<f32> {
109 return textureSample(tex, samp, FragCoord.xy / vec2<f32>(4.0, 4.0));
110 })");
111
112 utils::ComboRenderPipelineDescriptor descriptor;
113 descriptor.vertex.module = vsModule;
114 descriptor.cFragment.module = fsModule;
115 descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
116 descriptor.cTargets[0].format = kFormat;
117
118 wgpu::Sampler sampler = device.CreateSampler();
119
120 wgpu::RenderPipeline rp = device.CreateRenderPipeline(&descriptor);
121 wgpu::BindGroupLayout bgl = rp.GetBindGroupLayout(0);
122 wgpu::BindGroup bindGroup =
123 utils::MakeBindGroup(device, bgl, {{0, sampler}, {1, samplerView}});
124
125 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
126
127 utils::ComboRenderPassDescriptor renderPassDesc({renderView});
128 renderPassDesc.cColorAttachments[0].clearColor = {0.0f, 0.0f, 0.0f, 1.0f};
129 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
130 pass.SetPipeline(rp);
131 pass.SetBindGroup(0, bindGroup);
132 pass.Draw(6);
133 pass.EndPass();
134 wgpu::CommandBuffer commands = encoder.Finish();
135 queue.Submit(1, &commands);
136 }
137 };
138
139 // Test different mipmap levels
TEST_P(TextureSubresourceTest,MipmapLevelsTest)140 TEST_P(TextureSubresourceTest, MipmapLevelsTest) {
141 // TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES.
142 DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
143
144 // Create a texture with 2 mipmap levels and 1 layer
145 wgpu::Texture texture =
146 CreateTexture(2, 1,
147 wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment |
148 wgpu::TextureUsage::CopySrc);
149
150 // Create two views on different mipmap levels.
151 wgpu::TextureView samplerView = CreateTextureView(texture, 0, 0);
152 wgpu::TextureView renderView = CreateTextureView(texture, 1, 0);
153
154 // Draw a red triangle at the bottom-left half
155 DrawTriangle(samplerView);
156
157 // Sample from one subresource and draw into another subresource in the same texture
158 SampleAndDraw(samplerView, renderView);
159
160 // Verify that pixel at bottom-left corner is red, while pixel at top-right corner is background
161 // black in render view (mip level 1).
162 RGBA8 topRight = RGBA8::kBlack;
163 RGBA8 bottomLeft = RGBA8::kRed;
164 EXPECT_TEXTURE_EQ(&topRight, texture, {kSize / 2 - 1, 0}, {1, 1}, 1);
165 EXPECT_TEXTURE_EQ(&bottomLeft, texture, {0, kSize / 2 - 1}, {1, 1}, 1);
166 }
167
168 // Test different array layers
TEST_P(TextureSubresourceTest,ArrayLayersTest)169 TEST_P(TextureSubresourceTest, ArrayLayersTest) {
170 // TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES.
171 DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
172 // Create a texture with 1 mipmap level and 2 layers
173 wgpu::Texture texture =
174 CreateTexture(1, 2,
175 wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment |
176 wgpu::TextureUsage::CopySrc);
177
178 // Create two views on different layers
179 wgpu::TextureView samplerView = CreateTextureView(texture, 0, 0);
180 wgpu::TextureView renderView = CreateTextureView(texture, 0, 1);
181
182 // Draw a red triangle at the bottom-left half
183 DrawTriangle(samplerView);
184
185 // Sample from one subresource and draw into another subresource in the same texture
186 SampleAndDraw(samplerView, renderView);
187
188 // Verify that pixel at bottom-left corner is red, while pixel at top-right corner is background
189 // black in render view (array layer 1).
190 RGBA8 topRight = RGBA8::kBlack;
191 RGBA8 bottomLeft = RGBA8::kRed;
192 EXPECT_TEXTURE_EQ(&topRight, texture, {kSize - 1, 0, 1}, {1, 1});
193 EXPECT_TEXTURE_EQ(&bottomLeft, texture, {0, kSize - 1, 1}, {1, 1});
194 }
195
196 // TODO (yunchao.he@intel.com):
197 // * add tests for storage texture and sampler across miplevel or
198 // arraylayer dimensions in the same texture
199 //
200 // * add tests for copy operation upon texture subresource if needed
201 //
202 // * add tests for clear operation upon texture subresource if needed
203
204 DAWN_INSTANTIATE_TEST(TextureSubresourceTest,
205 D3D12Backend(),
206 MetalBackend(),
207 OpenGLBackend(),
208 OpenGLESBackend(),
209 VulkanBackend());
210