• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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