• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 "common/Assert.h"
18 #include "common/Constants.h"
19 #include "common/Math.h"
20 #include "utils/ComboRenderPipelineDescriptor.h"
21 #include "utils/WGPUHelpers.h"
22 
23 #include <array>
24 
25 constexpr static unsigned int kRTSize = 64;
26 constexpr wgpu::TextureFormat kDefaultFormat = wgpu::TextureFormat::RGBA8Unorm;
27 constexpr uint32_t kBytesPerTexel = 4;
28 
29 namespace {
Create2DTexture(wgpu::Device device,uint32_t width,uint32_t height,uint32_t arrayLayerCount,uint32_t mipLevelCount,wgpu::TextureUsage usage)30     wgpu::Texture Create2DTexture(wgpu::Device device,
31                                   uint32_t width,
32                                   uint32_t height,
33                                   uint32_t arrayLayerCount,
34                                   uint32_t mipLevelCount,
35                                   wgpu::TextureUsage usage) {
36         wgpu::TextureDescriptor descriptor;
37         descriptor.dimension = wgpu::TextureDimension::e2D;
38         descriptor.size.width = width;
39         descriptor.size.height = height;
40         descriptor.size.depthOrArrayLayers = arrayLayerCount;
41         descriptor.sampleCount = 1;
42         descriptor.format = kDefaultFormat;
43         descriptor.mipLevelCount = mipLevelCount;
44         descriptor.usage = usage;
45         return device.CreateTexture(&descriptor);
46     }
47 
Create3DTexture(wgpu::Device device,wgpu::Extent3D size,uint32_t mipLevelCount,wgpu::TextureUsage usage)48     wgpu::Texture Create3DTexture(wgpu::Device device,
49                                   wgpu::Extent3D size,
50                                   uint32_t mipLevelCount,
51                                   wgpu::TextureUsage usage) {
52         wgpu::TextureDescriptor descriptor;
53         descriptor.dimension = wgpu::TextureDimension::e3D;
54         descriptor.size = size;
55         descriptor.sampleCount = 1;
56         descriptor.format = kDefaultFormat;
57         descriptor.mipLevelCount = mipLevelCount;
58         descriptor.usage = usage;
59         return device.CreateTexture(&descriptor);
60     }
61 
CreateDefaultVertexShaderModule(wgpu::Device device)62     wgpu::ShaderModule CreateDefaultVertexShaderModule(wgpu::Device device) {
63         return utils::CreateShaderModule(device, R"(
64             struct VertexOut {
65                 [[location(0)]] texCoord : vec2<f32>;
66                 [[builtin(position)]] position : vec4<f32>;
67             };
68 
69             [[stage(vertex)]]
70             fn main([[builtin(vertex_index)]] VertexIndex : u32) -> VertexOut {
71                 var output : VertexOut;
72                 var pos = array<vec2<f32>, 6>(
73                                             vec2<f32>(-2., -2.),
74                                             vec2<f32>(-2.,  2.),
75                                             vec2<f32>( 2., -2.),
76                                             vec2<f32>(-2.,  2.),
77                                             vec2<f32>( 2., -2.),
78                                             vec2<f32>( 2.,  2.));
79                 var texCoord = array<vec2<f32>, 6>(
80                                                  vec2<f32>(0., 0.),
81                                                  vec2<f32>(0., 1.),
82                                                  vec2<f32>(1., 0.),
83                                                  vec2<f32>(0., 1.),
84                                                  vec2<f32>(1., 0.),
85                                                  vec2<f32>(1., 1.));
86                 output.position = vec4<f32>(pos[VertexIndex], 0., 1.);
87                 output.texCoord = texCoord[VertexIndex];
88                 return output;
89             }
90         )");
91     }
92 }  // anonymous namespace
93 
94 class TextureViewSamplingTest : public DawnTest {
95   protected:
96     // Generates an arbitrary pixel value per-layer-per-level, used for the "actual" uploaded
97     // textures and the "expected" results.
GenerateTestPixelValue(uint32_t layer,uint32_t level)98     static int GenerateTestPixelValue(uint32_t layer, uint32_t level) {
99         return static_cast<int>(level * 10) + static_cast<int>(layer + 1);
100     }
101 
SetUp()102     void SetUp() override {
103         DawnTest::SetUp();
104 
105         mRenderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
106 
107         wgpu::FilterMode kFilterMode = wgpu::FilterMode::Nearest;
108         wgpu::AddressMode kAddressMode = wgpu::AddressMode::ClampToEdge;
109 
110         wgpu::SamplerDescriptor samplerDescriptor = {};
111         samplerDescriptor.minFilter = kFilterMode;
112         samplerDescriptor.magFilter = kFilterMode;
113         samplerDescriptor.mipmapFilter = kFilterMode;
114         samplerDescriptor.addressModeU = kAddressMode;
115         samplerDescriptor.addressModeV = kAddressMode;
116         samplerDescriptor.addressModeW = kAddressMode;
117         mSampler = device.CreateSampler(&samplerDescriptor);
118 
119         mVSModule = CreateDefaultVertexShaderModule(device);
120     }
121 
initTexture(uint32_t arrayLayerCount,uint32_t mipLevelCount)122     void initTexture(uint32_t arrayLayerCount, uint32_t mipLevelCount) {
123         ASSERT(arrayLayerCount > 0 && mipLevelCount > 0);
124 
125         const uint32_t textureWidthLevel0 = 1 << mipLevelCount;
126         const uint32_t textureHeightLevel0 = 1 << mipLevelCount;
127         constexpr wgpu::TextureUsage kUsage =
128             wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding;
129         mTexture = Create2DTexture(device, textureWidthLevel0, textureHeightLevel0, arrayLayerCount,
130                                    mipLevelCount, kUsage);
131 
132         mDefaultTextureViewDescriptor.dimension = wgpu::TextureViewDimension::e2DArray;
133         mDefaultTextureViewDescriptor.format = kDefaultFormat;
134         mDefaultTextureViewDescriptor.baseMipLevel = 0;
135         mDefaultTextureViewDescriptor.mipLevelCount = mipLevelCount;
136         mDefaultTextureViewDescriptor.baseArrayLayer = 0;
137         mDefaultTextureViewDescriptor.arrayLayerCount = arrayLayerCount;
138 
139         // Create a texture with pixel = (0, 0, 0, level * 10 + layer + 1) at level `level` and
140         // layer `layer`.
141         static_assert((kTextureBytesPerRowAlignment % sizeof(RGBA8)) == 0,
142                       "Texture bytes per row alignment must be a multiple of sizeof(RGBA8).");
143         constexpr uint32_t kPixelsPerRowPitch = kTextureBytesPerRowAlignment / sizeof(RGBA8);
144         ASSERT_LE(textureWidthLevel0, kPixelsPerRowPitch);
145 
146         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
147         for (uint32_t layer = 0; layer < arrayLayerCount; ++layer) {
148             for (uint32_t level = 0; level < mipLevelCount; ++level) {
149                 const uint32_t texWidth = textureWidthLevel0 >> level;
150                 const uint32_t texHeight = textureHeightLevel0 >> level;
151 
152                 const int pixelValue = GenerateTestPixelValue(layer, level);
153 
154                 constexpr uint32_t kPaddedTexWidth = kPixelsPerRowPitch;
155                 std::vector<RGBA8> data(kPaddedTexWidth * texHeight, RGBA8(0, 0, 0, pixelValue));
156                 wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
157                     device, data.data(), data.size() * sizeof(RGBA8), wgpu::BufferUsage::CopySrc);
158                 wgpu::ImageCopyBuffer imageCopyBuffer =
159                     utils::CreateImageCopyBuffer(stagingBuffer, 0, kTextureBytesPerRowAlignment);
160                 wgpu::ImageCopyTexture imageCopyTexture =
161                     utils::CreateImageCopyTexture(mTexture, level, {0, 0, layer});
162                 wgpu::Extent3D copySize = {texWidth, texHeight, 1};
163                 encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copySize);
164             }
165         }
166         wgpu::CommandBuffer copy = encoder.Finish();
167         queue.Submit(1, &copy);
168     }
169 
Verify(const wgpu::TextureView & textureView,const char * fragmentShader,int expected)170     void Verify(const wgpu::TextureView& textureView, const char* fragmentShader, int expected) {
171         wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, fragmentShader);
172 
173         utils::ComboRenderPipelineDescriptor textureDescriptor;
174         textureDescriptor.vertex.module = mVSModule;
175         textureDescriptor.cFragment.module = fsModule;
176         textureDescriptor.cTargets[0].format = mRenderPass.colorFormat;
177 
178         wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&textureDescriptor);
179 
180         wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
181                                                          {{0, mSampler}, {1, textureView}});
182 
183         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
184         {
185             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&mRenderPass.renderPassInfo);
186             pass.SetPipeline(pipeline);
187             pass.SetBindGroup(0, bindGroup);
188             pass.Draw(6);
189             pass.EndPass();
190         }
191 
192         wgpu::CommandBuffer commands = encoder.Finish();
193         queue.Submit(1, &commands);
194 
195         RGBA8 expectedPixel(0, 0, 0, expected);
196         EXPECT_PIXEL_RGBA8_EQ(expectedPixel, mRenderPass.color, 0, 0);
197         EXPECT_PIXEL_RGBA8_EQ(expectedPixel, mRenderPass.color, mRenderPass.width - 1,
198                               mRenderPass.height - 1);
199         // TODO(jiawei.shao@intel.com): add tests for 3D textures once Dawn supports 3D textures
200     }
201 
Texture2DViewTest(uint32_t textureArrayLayers,uint32_t textureMipLevels,uint32_t textureViewBaseLayer,uint32_t textureViewBaseMipLevel)202     void Texture2DViewTest(uint32_t textureArrayLayers,
203                            uint32_t textureMipLevels,
204                            uint32_t textureViewBaseLayer,
205                            uint32_t textureViewBaseMipLevel) {
206         // TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES.
207         DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
208         ASSERT(textureViewBaseLayer < textureArrayLayers);
209         ASSERT(textureViewBaseMipLevel < textureMipLevels);
210 
211         initTexture(textureArrayLayers, textureMipLevels);
212 
213         wgpu::TextureViewDescriptor descriptor = mDefaultTextureViewDescriptor;
214         descriptor.dimension = wgpu::TextureViewDimension::e2D;
215         descriptor.baseArrayLayer = textureViewBaseLayer;
216         descriptor.arrayLayerCount = 1;
217         descriptor.baseMipLevel = textureViewBaseMipLevel;
218         descriptor.mipLevelCount = 1;
219         wgpu::TextureView textureView = mTexture.CreateView(&descriptor);
220 
221         const char* fragmentShader = R"(
222             [[group(0), binding(0)]] var sampler0 : sampler;
223             [[group(0), binding(1)]] var texture0 : texture_2d<f32>;
224 
225             [[stage(fragment)]]
226             fn main([[location(0)]] texCoord : vec2<f32>) -> [[location(0)]] vec4<f32> {
227                 return textureSample(texture0, sampler0, texCoord);
228             }
229         )";
230 
231         const int expected = GenerateTestPixelValue(textureViewBaseLayer, textureViewBaseMipLevel);
232         Verify(textureView, fragmentShader, expected);
233     }
234 
Texture2DArrayViewTest(uint32_t textureArrayLayers,uint32_t textureMipLevels,uint32_t textureViewBaseLayer,uint32_t textureViewBaseMipLevel)235     void Texture2DArrayViewTest(uint32_t textureArrayLayers,
236                                 uint32_t textureMipLevels,
237                                 uint32_t textureViewBaseLayer,
238                                 uint32_t textureViewBaseMipLevel) {
239         // TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES.
240         DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
241         ASSERT(textureViewBaseLayer < textureArrayLayers);
242         ASSERT(textureViewBaseMipLevel < textureMipLevels);
243 
244         // We always set the layer count of the texture view to be 3 to match the fragment shader in
245         // this test.
246         constexpr uint32_t kTextureViewLayerCount = 3;
247         ASSERT(textureArrayLayers >= textureViewBaseLayer + kTextureViewLayerCount);
248 
249         initTexture(textureArrayLayers, textureMipLevels);
250 
251         wgpu::TextureViewDescriptor descriptor = mDefaultTextureViewDescriptor;
252         descriptor.dimension = wgpu::TextureViewDimension::e2DArray;
253         descriptor.baseArrayLayer = textureViewBaseLayer;
254         descriptor.arrayLayerCount = kTextureViewLayerCount;
255         descriptor.baseMipLevel = textureViewBaseMipLevel;
256         descriptor.mipLevelCount = 1;
257         wgpu::TextureView textureView = mTexture.CreateView(&descriptor);
258 
259         const char* fragmentShader = R"(
260             [[group(0), binding(0)]] var sampler0 : sampler;
261             [[group(0), binding(1)]] var texture0 : texture_2d_array<f32>;
262 
263             [[stage(fragment)]]
264             fn main([[location(0)]] texCoord : vec2<f32>) -> [[location(0)]] vec4<f32> {
265                 return textureSample(texture0, sampler0, texCoord, 0) +
266                        textureSample(texture0, sampler0, texCoord, 1) +
267                        textureSample(texture0, sampler0, texCoord, 2);
268             }
269         )";
270 
271         int expected = 0;
272         for (int i = 0; i < static_cast<int>(kTextureViewLayerCount); ++i) {
273             expected += GenerateTestPixelValue(textureViewBaseLayer + i, textureViewBaseMipLevel);
274         }
275         Verify(textureView, fragmentShader, expected);
276     }
277 
CreateFragmentShaderForCubeMapFace(uint32_t layer,bool isCubeMapArray)278     std::string CreateFragmentShaderForCubeMapFace(uint32_t layer, bool isCubeMapArray) {
279         // Reference: https://en.wikipedia.org/wiki/Cube_mapping
280         const std::array<std::string, 6> kCoordsToCubeMapFace = {{
281             " 1.,  tc, -sc",  // Positive X
282             "-1.,  tc,  sc",  // Negative X
283             " sc,  1., -tc",  // Positive Y
284             " sc, -1.,  tc",  // Negative Y
285             " sc,  tc,  1.",  // Positive Z
286             "-sc,  tc, -1.",  // Negative Z
287         }};
288 
289         const std::string textureType = isCubeMapArray ? "texture_cube_array" : "texture_cube";
290         const uint32_t cubeMapArrayIndex = layer / 6;
291         const std::string coordToCubeMapFace = kCoordsToCubeMapFace[layer % 6];
292 
293         std::ostringstream stream;
294         stream << R"(
295             [[group(0), binding(0)]] var sampler0 : sampler;
296             [[group(0), binding(1)]] var texture0 : )"
297                << textureType << R"(<f32>;
298             [[stage(fragment)]]
299             fn main([[location(0)]] texCoord : vec2<f32>) -> [[location(0)]] vec4<f32> {
300                 var sc : f32 = 2.0 * texCoord.x - 1.0;
301                 var tc : f32 = 2.0 * texCoord.y - 1.0;
302                 return textureSample(texture0, sampler0, vec3<f32>()"
303                << coordToCubeMapFace << ")";
304 
305         if (isCubeMapArray) {
306             stream << ", " << cubeMapArrayIndex;
307         }
308 
309         stream << R"();
310             })";
311 
312         return stream.str();
313     }
314 
TextureCubeMapTest(uint32_t textureArrayLayers,uint32_t textureViewBaseLayer,uint32_t textureViewLayerCount,bool isCubeMapArray)315     void TextureCubeMapTest(uint32_t textureArrayLayers,
316                             uint32_t textureViewBaseLayer,
317                             uint32_t textureViewLayerCount,
318                             bool isCubeMapArray) {
319         // TODO(crbug.com/dawn/600): In OpenGL ES, cube map textures cannot be treated as arrays
320         // of 2D textures. Find a workaround.
321         DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
322         constexpr uint32_t kMipLevels = 1u;
323         initTexture(textureArrayLayers, kMipLevels);
324 
325         ASSERT_TRUE((textureViewLayerCount == 6) ||
326                     (isCubeMapArray && textureViewLayerCount % 6 == 0));
327         wgpu::TextureViewDimension dimension = (isCubeMapArray)
328                                                    ? wgpu::TextureViewDimension::CubeArray
329                                                    : wgpu::TextureViewDimension::Cube;
330 
331         wgpu::TextureViewDescriptor descriptor = mDefaultTextureViewDescriptor;
332         descriptor.dimension = dimension;
333         descriptor.baseArrayLayer = textureViewBaseLayer;
334         descriptor.arrayLayerCount = textureViewLayerCount;
335 
336         wgpu::TextureView cubeMapTextureView = mTexture.CreateView(&descriptor);
337 
338         // Check the data in the every face of the cube map (array) texture view.
339         for (uint32_t layer = 0; layer < textureViewLayerCount; ++layer) {
340             const std::string& fragmentShader =
341                 CreateFragmentShaderForCubeMapFace(layer, isCubeMapArray);
342 
343             int expected = GenerateTestPixelValue(textureViewBaseLayer + layer, 0);
344             Verify(cubeMapTextureView, fragmentShader.c_str(), expected);
345         }
346     }
347 
348     wgpu::Sampler mSampler;
349     wgpu::Texture mTexture;
350     wgpu::TextureViewDescriptor mDefaultTextureViewDescriptor;
351     wgpu::ShaderModule mVSModule;
352     utils::BasicRenderPass mRenderPass;
353 };
354 
355 // Test drawing a rect with a 2D array texture.
TEST_P(TextureViewSamplingTest,Default2DArrayTexture)356 TEST_P(TextureViewSamplingTest, Default2DArrayTexture) {
357     // TODO(cwallez@chromium.org) understand what the issue is
358     DAWN_SUPPRESS_TEST_IF(IsVulkan() && IsNvidia());
359 
360     constexpr uint32_t kLayers = 3;
361     constexpr uint32_t kMipLevels = 1;
362     initTexture(kLayers, kMipLevels);
363 
364     wgpu::TextureViewDescriptor descriptor;
365     descriptor.dimension = wgpu::TextureViewDimension::e2DArray;
366     wgpu::TextureView textureView = mTexture.CreateView(&descriptor);
367 
368     const char* fragmentShader = R"(
369             [[group(0), binding(0)]] var sampler0 : sampler;
370             [[group(0), binding(1)]] var texture0 : texture_2d_array<f32>;
371 
372             [[stage(fragment)]]
373             fn main([[location(0)]] texCoord : vec2<f32>) -> [[location(0)]] vec4<f32> {
374                 return textureSample(texture0, sampler0, texCoord, 0) +
375                        textureSample(texture0, sampler0, texCoord, 1) +
376                        textureSample(texture0, sampler0, texCoord, 2);
377             }
378         )";
379 
380     const int expected =
381         GenerateTestPixelValue(0, 0) + GenerateTestPixelValue(1, 0) + GenerateTestPixelValue(2, 0);
382     Verify(textureView, fragmentShader, expected);
383 }
384 
385 // Test sampling from a 2D texture view created on a 2D array texture.
TEST_P(TextureViewSamplingTest,Texture2DViewOn2DArrayTexture)386 TEST_P(TextureViewSamplingTest, Texture2DViewOn2DArrayTexture) {
387     Texture2DViewTest(6, 1, 4, 0);
388 }
389 
390 // Test sampling from a 2D array texture view created on a 2D array texture.
TEST_P(TextureViewSamplingTest,Texture2DArrayViewOn2DArrayTexture)391 TEST_P(TextureViewSamplingTest, Texture2DArrayViewOn2DArrayTexture) {
392     DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel());
393     Texture2DArrayViewTest(6, 1, 2, 0);
394 }
395 
396 // Test sampling from a 2D texture view created on a mipmap level of a 2D texture.
TEST_P(TextureViewSamplingTest,Texture2DViewOnOneLevelOf2DTexture)397 TEST_P(TextureViewSamplingTest, Texture2DViewOnOneLevelOf2DTexture) {
398     Texture2DViewTest(1, 6, 0, 4);
399 }
400 
401 // Test sampling from a 2D texture view created on a mipmap level of a 2D array texture layer.
TEST_P(TextureViewSamplingTest,Texture2DViewOnOneLevelOf2DArrayTexture)402 TEST_P(TextureViewSamplingTest, Texture2DViewOnOneLevelOf2DArrayTexture) {
403     Texture2DViewTest(6, 6, 3, 4);
404 }
405 
406 // Test sampling from a 2D array texture view created on a mipmap level of a 2D array texture.
TEST_P(TextureViewSamplingTest,Texture2DArrayViewOnOneLevelOf2DArrayTexture)407 TEST_P(TextureViewSamplingTest, Texture2DArrayViewOnOneLevelOf2DArrayTexture) {
408     DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel());
409     Texture2DArrayViewTest(6, 6, 2, 4);
410 }
411 
412 // Test sampling from a cube map texture view that covers a whole 2D array texture.
TEST_P(TextureViewSamplingTest,TextureCubeMapOnWholeTexture)413 TEST_P(TextureViewSamplingTest, TextureCubeMapOnWholeTexture) {
414     constexpr uint32_t kTotalLayers = 6;
415     TextureCubeMapTest(kTotalLayers, 0, kTotalLayers, false);
416 }
417 
418 // Test sampling from a cube map texture view that covers a sub part of a 2D array texture.
TEST_P(TextureViewSamplingTest,TextureCubeMapViewOnPartOfTexture)419 TEST_P(TextureViewSamplingTest, TextureCubeMapViewOnPartOfTexture) {
420     TextureCubeMapTest(10, 2, 6, false);
421 }
422 
423 // Test sampling from a cube map texture view that covers the last layer of a 2D array texture.
TEST_P(TextureViewSamplingTest,TextureCubeMapViewCoveringLastLayer)424 TEST_P(TextureViewSamplingTest, TextureCubeMapViewCoveringLastLayer) {
425     constexpr uint32_t kTotalLayers = 10;
426     constexpr uint32_t kBaseLayer = 4;
427     TextureCubeMapTest(kTotalLayers, kBaseLayer, kTotalLayers - kBaseLayer, false);
428 }
429 
430 // Test sampling from a cube map texture array view that covers a whole 2D array texture.
TEST_P(TextureViewSamplingTest,TextureCubeMapArrayOnWholeTexture)431 TEST_P(TextureViewSamplingTest, TextureCubeMapArrayOnWholeTexture) {
432     constexpr uint32_t kTotalLayers = 12;
433     TextureCubeMapTest(kTotalLayers, 0, kTotalLayers, true);
434 }
435 
436 // Test sampling from a cube map texture array view that covers a sub part of a 2D array texture.
TEST_P(TextureViewSamplingTest,TextureCubeMapArrayViewOnPartOfTexture)437 TEST_P(TextureViewSamplingTest, TextureCubeMapArrayViewOnPartOfTexture) {
438     // Test failing on the GPU FYI Mac Pro (AMD), see
439     // https://bugs.chromium.org/p/dawn/issues/detail?id=58
440     DAWN_SUPPRESS_TEST_IF(IsMacOS() && IsMetal() && IsAMD());
441 
442     TextureCubeMapTest(20, 3, 12, true);
443 }
444 
445 // Test sampling from a cube map texture array view that covers the last layer of a 2D array
446 // texture.
TEST_P(TextureViewSamplingTest,TextureCubeMapArrayViewCoveringLastLayer)447 TEST_P(TextureViewSamplingTest, TextureCubeMapArrayViewCoveringLastLayer) {
448     // Test failing on the GPU FYI Mac Pro (AMD), see
449     // https://bugs.chromium.org/p/dawn/issues/detail?id=58
450     DAWN_SUPPRESS_TEST_IF(IsMacOS() && IsMetal() && IsAMD());
451 
452     constexpr uint32_t kTotalLayers = 20;
453     constexpr uint32_t kBaseLayer = 8;
454     TextureCubeMapTest(kTotalLayers, kBaseLayer, kTotalLayers - kBaseLayer, true);
455 }
456 
457 // Test sampling from a cube map array texture view that only has a single cube map.
TEST_P(TextureViewSamplingTest,TextureCubeMapArrayViewSingleCubeMap)458 TEST_P(TextureViewSamplingTest, TextureCubeMapArrayViewSingleCubeMap) {
459     // Test failing on the GPU FYI Mac Pro (AMD), see
460     // https://bugs.chromium.org/p/dawn/issues/detail?id=58
461     DAWN_SUPPRESS_TEST_IF(IsMacOS() && IsMetal() && IsAMD());
462 
463     TextureCubeMapTest(20, 7, 6, true);
464 }
465 
466 class TextureViewRenderingTest : public DawnTest {
467   protected:
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension dimension,uint32_t layerCount,uint32_t levelCount,uint32_t textureViewBaseLayer,uint32_t textureViewBaseLevel,uint32_t textureWidthLevel0,uint32_t textureHeightLevel0)468     void TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension dimension,
469                                            uint32_t layerCount,
470                                            uint32_t levelCount,
471                                            uint32_t textureViewBaseLayer,
472                                            uint32_t textureViewBaseLevel,
473                                            uint32_t textureWidthLevel0,
474                                            uint32_t textureHeightLevel0) {
475         ASSERT(dimension == wgpu::TextureViewDimension::e2D ||
476                dimension == wgpu::TextureViewDimension::e2DArray);
477         ASSERT_LT(textureViewBaseLayer, layerCount);
478         ASSERT_LT(textureViewBaseLevel, levelCount);
479 
480         constexpr wgpu::TextureUsage kUsage =
481             wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
482         wgpu::Texture texture = Create2DTexture(device, textureWidthLevel0, textureHeightLevel0,
483                                                 layerCount, levelCount, kUsage);
484 
485         wgpu::TextureViewDescriptor descriptor;
486         descriptor.format = kDefaultFormat;
487         descriptor.dimension = dimension;
488         descriptor.baseArrayLayer = textureViewBaseLayer;
489         descriptor.arrayLayerCount = 1;
490         descriptor.baseMipLevel = textureViewBaseLevel;
491         descriptor.mipLevelCount = 1;
492         wgpu::TextureView textureView = texture.CreateView(&descriptor);
493 
494         wgpu::ShaderModule vsModule = CreateDefaultVertexShaderModule(device);
495 
496         // Clear textureView with Red(255, 0, 0, 255) and render Green(0, 255, 0, 255) into it
497         utils::ComboRenderPassDescriptor renderPassInfo({textureView});
498         renderPassInfo.cColorAttachments[0].clearColor = {1.0f, 0.0f, 0.0f, 1.0f};
499 
500         const char* oneColorFragmentShader = R"(
501             [[stage(fragment)]] fn main([[location(0)]] texCoord : vec2<f32>) ->
502                 [[location(0)]] vec4<f32> {
503                 return vec4<f32>(0.0, 1.0, 0.0, 1.0);
504             }
505         )";
506         wgpu::ShaderModule oneColorFsModule =
507             utils::CreateShaderModule(device, oneColorFragmentShader);
508 
509         utils::ComboRenderPipelineDescriptor pipelineDescriptor;
510         pipelineDescriptor.vertex.module = vsModule;
511         pipelineDescriptor.cFragment.module = oneColorFsModule;
512         pipelineDescriptor.cTargets[0].format = kDefaultFormat;
513 
514         wgpu::RenderPipeline oneColorPipeline = device.CreateRenderPipeline(&pipelineDescriptor);
515 
516         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
517         {
518             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassInfo);
519             pass.SetPipeline(oneColorPipeline);
520             pass.Draw(6);
521             pass.EndPass();
522         }
523 
524         wgpu::CommandBuffer commands = encoder.Finish();
525         queue.Submit(1, &commands);
526 
527         // Check if the right pixels (Green) have been written into the right part of the texture.
528         uint32_t textureViewWidth = std::max(1u, textureWidthLevel0 >> textureViewBaseLevel);
529         uint32_t textureViewHeight = std::max(1u, textureHeightLevel0 >> textureViewBaseLevel);
530         uint32_t bytesPerRow =
531             Align(kBytesPerTexel * textureWidthLevel0, kTextureBytesPerRowAlignment);
532         uint32_t expectedDataSize =
533             bytesPerRow / kBytesPerTexel * (textureWidthLevel0 - 1) + textureHeightLevel0;
534         constexpr RGBA8 kExpectedPixel(0, 255, 0, 255);
535         std::vector<RGBA8> expected(expectedDataSize, kExpectedPixel);
536         EXPECT_TEXTURE_EQ(expected.data(), texture, {0, 0, textureViewBaseLayer},
537                           {textureViewWidth, textureViewHeight}, textureViewBaseLevel);
538     }
539 };
540 
541 // Test rendering into a 2D texture view created on a mipmap level of a 2D texture.
TEST_P(TextureViewRenderingTest,Texture2DViewOnALevelOf2DTextureAsColorAttachment)542 TEST_P(TextureViewRenderingTest, Texture2DViewOnALevelOf2DTextureAsColorAttachment) {
543     constexpr uint32_t kLayers = 1;
544     constexpr uint32_t kMipLevels = 4;
545     constexpr uint32_t kBaseLayer = 0;
546 
547     // Rendering into the first level
548     {
549         constexpr uint32_t kBaseLevel = 0;
550         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
551                                           kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
552     }
553 
554     // Rendering into the last level
555     {
556         constexpr uint32_t kBaseLevel = kMipLevels - 1;
557         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
558                                           kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
559     }
560 }
561 
562 // Test rendering into a 2D texture view created on a mipmap level of a rectangular 2D texture.
TEST_P(TextureViewRenderingTest,Texture2DViewOnALevelOfRectangular2DTextureAsColorAttachment)563 TEST_P(TextureViewRenderingTest, Texture2DViewOnALevelOfRectangular2DTextureAsColorAttachment) {
564     constexpr uint32_t kLayers = 1;
565     constexpr uint32_t kMipLevels = 4;
566     constexpr uint32_t kBaseLayer = 0;
567 
568     // Rendering into the first level
569     {
570         constexpr uint32_t kBaseLevel = 0;
571         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
572                                           kBaseLayer, kBaseLevel, 1 << kMipLevels,
573                                           1 << (kMipLevels - 2));
574         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
575                                           kBaseLayer, kBaseLevel, 1 << (kMipLevels - 2),
576                                           1 << kMipLevels);
577     }
578 
579     // Rendering into the last level
580     {
581         constexpr uint32_t kBaseLevel = kMipLevels - 1;
582         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
583                                           kBaseLayer, kBaseLevel, 1 << kMipLevels,
584                                           1 << (kMipLevels - 2));
585         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
586                                           kBaseLayer, kBaseLevel, 1 << (kMipLevels - 2),
587                                           1 << kMipLevels);
588     }
589 }
590 
591 // Test rendering into a 2D texture view created on a layer of a 2D array texture.
TEST_P(TextureViewRenderingTest,Texture2DViewOnALayerOf2DArrayTextureAsColorAttachment)592 TEST_P(TextureViewRenderingTest, Texture2DViewOnALayerOf2DArrayTextureAsColorAttachment) {
593     constexpr uint32_t kMipLevels = 1;
594     constexpr uint32_t kBaseLevel = 0;
595     constexpr uint32_t kLayers = 10;
596 
597     // Rendering into the first layer
598     {
599         constexpr uint32_t kBaseLayer = 0;
600         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
601                                           kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
602     }
603 
604     // Rendering into the last layer
605     {
606         constexpr uint32_t kBaseLayer = kLayers - 1;
607         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
608                                           kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
609     }
610 }
611 
612 // Test rendering into a 1-layer 2D array texture view created on a mipmap level of a 2D texture.
TEST_P(TextureViewRenderingTest,Texture2DArrayViewOnALevelOf2DTextureAsColorAttachment)613 TEST_P(TextureViewRenderingTest, Texture2DArrayViewOnALevelOf2DTextureAsColorAttachment) {
614     constexpr uint32_t kLayers = 1;
615     constexpr uint32_t kMipLevels = 4;
616     constexpr uint32_t kBaseLayer = 0;
617 
618     // Rendering into the first level
619     {
620         constexpr uint32_t kBaseLevel = 0;
621         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels,
622                                           kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
623     }
624 
625     // Rendering into the last level
626     {
627         constexpr uint32_t kBaseLevel = kMipLevels - 1;
628         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels,
629                                           kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
630     }
631 }
632 
633 // Test rendering into a 1-layer 2D array texture view created on a layer of a 2D array texture.
TEST_P(TextureViewRenderingTest,Texture2DArrayViewOnALayerOf2DArrayTextureAsColorAttachment)634 TEST_P(TextureViewRenderingTest, Texture2DArrayViewOnALayerOf2DArrayTextureAsColorAttachment) {
635     constexpr uint32_t kMipLevels = 1;
636     constexpr uint32_t kBaseLevel = 0;
637     constexpr uint32_t kLayers = 10;
638 
639     // Rendering into the first layer
640     {
641         constexpr uint32_t kBaseLayer = 0;
642         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels,
643                                           kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
644     }
645 
646     // Rendering into the last layer
647     {
648         constexpr uint32_t kBaseLayer = kLayers - 1;
649         TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels,
650                                           kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
651     }
652 }
653 
654 DAWN_INSTANTIATE_TEST(TextureViewSamplingTest,
655                       D3D12Backend(),
656                       MetalBackend(),
657                       OpenGLBackend(),
658                       OpenGLESBackend(),
659                       VulkanBackend());
660 
661 DAWN_INSTANTIATE_TEST(TextureViewRenderingTest,
662                       D3D12Backend(),
663                       MetalBackend(),
664                       OpenGLBackend(),
665                       OpenGLESBackend(),
666                       VulkanBackend());
667 
668 class TextureViewTest : public DawnTest {};
669 
670 // This is a regression test for crbug.com/dawn/399 where creating a texture view with only copy
671 // usage would cause the Vulkan validation layers to warn
TEST_P(TextureViewTest,OnlyCopySrcDst)672 TEST_P(TextureViewTest, OnlyCopySrcDst) {
673     wgpu::TextureDescriptor descriptor;
674     descriptor.size = {4, 4, 1};
675     descriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
676     descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
677 
678     wgpu::Texture texture = device.CreateTexture(&descriptor);
679     wgpu::TextureView view = texture.CreateView();
680 }
681 
682 // Test that a texture view can be created from a destroyed texture without
683 // backend errors.
TEST_P(TextureViewTest,DestroyedTexture)684 TEST_P(TextureViewTest, DestroyedTexture) {
685     wgpu::TextureDescriptor descriptor;
686     descriptor.size = {4, 4, 2};
687     descriptor.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst;
688     descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
689 
690     wgpu::Texture texture = device.CreateTexture(&descriptor);
691     texture.Destroy();
692 
693     wgpu::TextureViewDescriptor viewDesc = {};
694     viewDesc.baseArrayLayer = 1;
695     viewDesc.arrayLayerCount = 1;
696     wgpu::TextureView view = texture.CreateView(&viewDesc);
697 }
698 
699 DAWN_INSTANTIATE_TEST(TextureViewTest,
700                       D3D12Backend(),
701                       MetalBackend(),
702                       OpenGLBackend(),
703                       OpenGLESBackend(),
704                       VulkanBackend());
705 
706 class TextureView3DTest : public DawnTest {};
707 
708 // Test that 3D textures and 3D texture views can be created successfully
TEST_P(TextureView3DTest,BasicTest)709 TEST_P(TextureView3DTest, BasicTest) {
710     wgpu::Texture texture =
711         Create3DTexture(device, {4, 4, 4}, 3, wgpu::TextureUsage::TextureBinding);
712     wgpu::TextureView view = texture.CreateView();
713 }
714 
715 DAWN_INSTANTIATE_TEST(TextureView3DTest,
716                       D3D12Backend(),
717                       MetalBackend(),
718                       OpenGLBackend(),
719                       OpenGLESBackend(),
720                       VulkanBackend());
721