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, ©Size);
164 }
165 }
166 wgpu::CommandBuffer copy = encoder.Finish();
167 queue.Submit(1, ©);
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