• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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 <array>
18 #include "common/Constants.h"
19 #include "common/Math.h"
20 #include "utils/TestUtils.h"
21 #include "utils/TextureUtils.h"
22 #include "utils/WGPUHelpers.h"
23 
24 // For MinimumBufferSpec bytesPerRow and rowsPerImage, compute a default from the copy extent.
25 constexpr uint32_t kStrideComputeDefault = 0xFFFF'FFFEul;
26 
27 constexpr wgpu::TextureFormat kDefaultFormat = wgpu::TextureFormat::RGBA8Unorm;
28 
29 class CopyTests {
30   protected:
31     struct TextureSpec {
32         wgpu::TextureFormat format = kDefaultFormat;
33         wgpu::Origin3D copyOrigin = {0, 0, 0};
34         wgpu::Extent3D textureSize;
35         uint32_t copyLevel = 0;
36         uint32_t levelCount = 1;
37     };
38 
39     struct BufferSpec {
40         uint64_t size;
41         uint64_t offset;
42         uint32_t bytesPerRow;
43         uint32_t rowsPerImage;
44     };
45 
GetExpectedTextureData(const utils::TextureDataCopyLayout & layout)46     static std::vector<uint8_t> GetExpectedTextureData(const utils::TextureDataCopyLayout& layout) {
47         uint32_t bytesPerTexelBlock = layout.bytesPerRow / layout.texelBlocksPerRow;
48         std::vector<uint8_t> textureData(layout.byteLength);
49         for (uint32_t layer = 0; layer < layout.mipSize.depthOrArrayLayers; ++layer) {
50             const uint32_t byteOffsetPerSlice = layout.bytesPerImage * layer;
51             for (uint32_t y = 0; y < layout.mipSize.height; ++y) {
52                 for (uint32_t x = 0; x < layout.mipSize.width * bytesPerTexelBlock; ++x) {
53                     uint32_t i = x + y * layout.bytesPerRow;
54                     textureData[byteOffsetPerSlice + i] =
55                         static_cast<uint8_t>((x + 1 + (layer + 1) * y) % 256);
56                 }
57             }
58         }
59         return textureData;
60     }
61 
62     // TODO(crbug.com/dawn/818): remove this function when all the tests in this file support
63     // testing arbitrary formats.
GetExpectedTextureDataRGBA8(const utils::TextureDataCopyLayout & layout)64     static std::vector<RGBA8> GetExpectedTextureDataRGBA8(
65         const utils::TextureDataCopyLayout& layout) {
66         std::vector<RGBA8> textureData(layout.texelBlockCount);
67         for (uint32_t layer = 0; layer < layout.mipSize.depthOrArrayLayers; ++layer) {
68             const uint32_t texelIndexOffsetPerSlice = layout.texelBlocksPerImage * layer;
69             for (uint32_t y = 0; y < layout.mipSize.height; ++y) {
70                 for (uint32_t x = 0; x < layout.mipSize.width; ++x) {
71                     uint32_t i = x + y * layout.texelBlocksPerRow;
72                     textureData[texelIndexOffsetPerSlice + i] =
73                         RGBA8(static_cast<uint8_t>((x + layer * x) % 256),
74                               static_cast<uint8_t>((y + layer * y) % 256),
75                               static_cast<uint8_t>(x / 256), static_cast<uint8_t>(y / 256));
76                 }
77             }
78         }
79 
80         return textureData;
81     }
82 
MinimumBufferSpec(uint32_t width,uint32_t height,uint32_t depth=1,wgpu::TextureFormat format=kDefaultFormat)83     static BufferSpec MinimumBufferSpec(uint32_t width,
84                                         uint32_t height,
85                                         uint32_t depth = 1,
86                                         wgpu::TextureFormat format = kDefaultFormat) {
87         return MinimumBufferSpec({width, height, depth}, kStrideComputeDefault,
88                                  depth == 1 ? wgpu::kCopyStrideUndefined : kStrideComputeDefault,
89                                  format);
90     }
91 
MinimumBufferSpec(wgpu::Extent3D copyExtent,uint32_t overrideBytesPerRow=kStrideComputeDefault,uint32_t overrideRowsPerImage=kStrideComputeDefault,wgpu::TextureFormat format=kDefaultFormat)92     static BufferSpec MinimumBufferSpec(wgpu::Extent3D copyExtent,
93                                         uint32_t overrideBytesPerRow = kStrideComputeDefault,
94                                         uint32_t overrideRowsPerImage = kStrideComputeDefault,
95                                         wgpu::TextureFormat format = kDefaultFormat) {
96         uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(format, copyExtent.width);
97         if (overrideBytesPerRow != kStrideComputeDefault) {
98             bytesPerRow = overrideBytesPerRow;
99         }
100         uint32_t rowsPerImage = copyExtent.height;
101         if (overrideRowsPerImage != kStrideComputeDefault) {
102             rowsPerImage = overrideRowsPerImage;
103         }
104 
105         uint32_t totalDataSize =
106             utils::RequiredBytesInCopy(bytesPerRow, rowsPerImage, copyExtent, format);
107         return {totalDataSize, 0, bytesPerRow, rowsPerImage};
108     }
CopyTextureData(uint32_t bytesPerTexelBlock,const void * srcData,uint32_t widthInBlocks,uint32_t heightInBlocks,uint32_t depthInBlocks,uint32_t srcBytesPerRow,uint32_t srcRowsPerImage,void * dstData,uint32_t dstBytesPerRow,uint32_t dstRowsPerImage)109     static void CopyTextureData(uint32_t bytesPerTexelBlock,
110                                 const void* srcData,
111                                 uint32_t widthInBlocks,
112                                 uint32_t heightInBlocks,
113                                 uint32_t depthInBlocks,
114                                 uint32_t srcBytesPerRow,
115                                 uint32_t srcRowsPerImage,
116                                 void* dstData,
117                                 uint32_t dstBytesPerRow,
118                                 uint32_t dstRowsPerImage) {
119         for (unsigned int z = 0; z < depthInBlocks; ++z) {
120             uint32_t srcDepthOffset = z * srcBytesPerRow * srcRowsPerImage;
121             uint32_t dstDepthOffset = z * dstBytesPerRow * dstRowsPerImage;
122             for (unsigned int y = 0; y < heightInBlocks; ++y) {
123                 memcpy(static_cast<uint8_t*>(dstData) + dstDepthOffset + y * dstBytesPerRow,
124                        static_cast<const uint8_t*>(srcData) + srcDepthOffset + y * srcBytesPerRow,
125                        widthInBlocks * bytesPerTexelBlock);
126             }
127         }
128     }
129 };
130 
131 class CopyTests_T2B : public CopyTests, public DawnTest {
132   protected:
DoTest(const TextureSpec & textureSpec,const BufferSpec & bufferSpec,const wgpu::Extent3D & copySize,wgpu::TextureDimension dimension=wgpu::TextureDimension::e2D)133     void DoTest(const TextureSpec& textureSpec,
134                 const BufferSpec& bufferSpec,
135                 const wgpu::Extent3D& copySize,
136                 wgpu::TextureDimension dimension = wgpu::TextureDimension::e2D) {
137         // TODO(crbug.com/dawn/818): support testing arbitrary formats
138         ASSERT_EQ(kDefaultFormat, textureSpec.format);
139 
140         const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(textureSpec.format);
141         // Create a texture that is `width` x `height` with (`level` + 1) mip levels.
142         wgpu::TextureDescriptor descriptor;
143         descriptor.dimension = dimension;
144         descriptor.size = textureSpec.textureSize;
145         descriptor.sampleCount = 1;
146         descriptor.format = textureSpec.format;
147         descriptor.mipLevelCount = textureSpec.levelCount;
148         descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc;
149         wgpu::Texture texture = device.CreateTexture(&descriptor);
150 
151         // Layout for initial data upload to texture.
152         // Some parts of this result are also reused later.
153         const utils::TextureDataCopyLayout copyLayout =
154             utils::GetTextureDataCopyLayoutForTextureAtLevel(
155                 textureSpec.format, textureSpec.textureSize, textureSpec.copyLevel, dimension);
156 
157         // Initialize the source texture
158         std::vector<RGBA8> textureArrayData = GetExpectedTextureDataRGBA8(copyLayout);
159         {
160             wgpu::ImageCopyTexture imageCopyTexture =
161                 utils::CreateImageCopyTexture(texture, textureSpec.copyLevel, {0, 0, 0});
162             wgpu::TextureDataLayout textureDataLayout =
163                 utils::CreateTextureDataLayout(0, copyLayout.bytesPerRow, copyLayout.rowsPerImage);
164             queue.WriteTexture(&imageCopyTexture, textureArrayData.data(), copyLayout.byteLength,
165                                &textureDataLayout, &copyLayout.mipSize);
166         }
167 
168         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
169 
170         // Create a buffer of `size` and populate it with empty data (0,0,0,0) Note:
171         // Prepopulating the buffer with empty data ensures that there is not random data in the
172         // expectation and helps ensure that the padding due to the bytes per row is not modified
173         // by the copy.
174         wgpu::BufferDescriptor bufferDesc;
175         bufferDesc.size = bufferSpec.size;
176         bufferDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
177         wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
178 
179         {
180             wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
181                 texture, textureSpec.copyLevel, textureSpec.copyOrigin);
182             wgpu::ImageCopyBuffer imageCopyBuffer = utils::CreateImageCopyBuffer(
183                 buffer, bufferSpec.offset, bufferSpec.bytesPerRow, bufferSpec.rowsPerImage);
184             encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &copySize);
185         }
186 
187         wgpu::CommandBuffer commands = encoder.Finish();
188         queue.Submit(1, &commands);
189 
190         uint64_t bufferOffset = bufferSpec.offset;
191 
192         uint32_t copyLayer = copySize.depthOrArrayLayers;
193         uint32_t copyDepth = 1;
194         if (dimension == wgpu::TextureDimension::e3D) {
195             copyLayer = 1;
196             copyDepth = copySize.depthOrArrayLayers;
197         }
198 
199         const wgpu::Extent3D copySizePerLayer = {copySize.width, copySize.height, copyDepth};
200         // Texels in single layer.
201         const uint32_t texelCountInCopyRegion = utils::GetTexelCountInCopyRegion(
202             bufferSpec.bytesPerRow, bufferSpec.rowsPerImage, copySizePerLayer, textureSpec.format);
203         const uint32_t maxArrayLayer = textureSpec.copyOrigin.z + copyLayer;
204         std::vector<RGBA8> expected(texelCountInCopyRegion);
205         for (uint32_t layer = textureSpec.copyOrigin.z; layer < maxArrayLayer; ++layer) {
206             // Copy the data used to create the upload buffer in the specified copy region to have
207             // the same format as the expected buffer data.
208             std::fill(expected.begin(), expected.end(), RGBA8());
209             const uint32_t texelIndexOffset = copyLayout.texelBlocksPerImage * layer;
210             const uint32_t expectedTexelArrayDataStartIndex =
211                 texelIndexOffset + (textureSpec.copyOrigin.x +
212                                     textureSpec.copyOrigin.y * copyLayout.texelBlocksPerRow);
213 
214             CopyTextureData(bytesPerTexel,
215                             textureArrayData.data() + expectedTexelArrayDataStartIndex,
216                             copySize.width, copySize.height, copyDepth, copyLayout.bytesPerRow,
217                             copyLayout.rowsPerImage, expected.data(), bufferSpec.bytesPerRow,
218                             bufferSpec.rowsPerImage);
219 
220             EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<const uint32_t*>(expected.data()), buffer,
221                                        bufferOffset, static_cast<uint32_t>(expected.size()))
222                 << "Texture to Buffer copy failed copying region [(" << textureSpec.copyOrigin.x
223                 << ", " << textureSpec.copyOrigin.y << ", " << textureSpec.copyOrigin.z << "), ("
224                 << textureSpec.copyOrigin.x + copySize.width << ", "
225                 << textureSpec.copyOrigin.y + copySize.height << ", "
226                 << textureSpec.copyOrigin.z + copySize.depthOrArrayLayers << ")) from "
227                 << textureSpec.textureSize.width << " x " << textureSpec.textureSize.height
228                 << " texture at mip level " << textureSpec.copyLevel << " layer " << layer << " to "
229                 << bufferSpec.size << "-byte buffer with offset " << bufferOffset
230                 << " and bytes per row " << bufferSpec.bytesPerRow << std::endl;
231 
232             bufferOffset += bufferSpec.bytesPerRow * bufferSpec.rowsPerImage;
233         }
234     }
235 };
236 
237 class CopyTests_B2T : public CopyTests, public DawnTest {
238   protected:
FillBufferData(RGBA8 * data,size_t count)239     static void FillBufferData(RGBA8* data, size_t count) {
240         for (size_t i = 0; i < count; ++i) {
241             data[i] = RGBA8(static_cast<uint8_t>(i % 256), static_cast<uint8_t>((i / 256) % 256),
242                             static_cast<uint8_t>((i / 256 / 256) % 256), 255);
243         }
244     }
245 
DoTest(const TextureSpec & textureSpec,const BufferSpec & bufferSpec,const wgpu::Extent3D & copySize,wgpu::TextureDimension dimension=wgpu::TextureDimension::e2D)246     void DoTest(const TextureSpec& textureSpec,
247                 const BufferSpec& bufferSpec,
248                 const wgpu::Extent3D& copySize,
249                 wgpu::TextureDimension dimension = wgpu::TextureDimension::e2D) {
250         // TODO(crbug.com/dawn/818): support testing arbitrary formats
251         ASSERT_EQ(kDefaultFormat, textureSpec.format);
252         // Create a buffer of size `size` and populate it with data
253         const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(textureSpec.format);
254         std::vector<RGBA8> bufferData(bufferSpec.size / bytesPerTexel);
255         FillBufferData(bufferData.data(), bufferData.size());
256         wgpu::Buffer buffer =
257             utils::CreateBufferFromData(device, bufferData.data(), bufferSpec.size,
258                                         wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst);
259 
260         // Create a texture that is `width` x `height` with (`level` + 1) mip levels.
261         wgpu::TextureDescriptor descriptor;
262         descriptor.dimension = dimension;
263         descriptor.size = textureSpec.textureSize;
264         descriptor.sampleCount = 1;
265         descriptor.format = textureSpec.format;
266         descriptor.mipLevelCount = textureSpec.levelCount;
267         descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc;
268         wgpu::Texture texture = device.CreateTexture(&descriptor);
269 
270         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
271 
272         wgpu::ImageCopyBuffer imageCopyBuffer = utils::CreateImageCopyBuffer(
273             buffer, bufferSpec.offset, bufferSpec.bytesPerRow, bufferSpec.rowsPerImage);
274         wgpu::ImageCopyTexture imageCopyTexture =
275             utils::CreateImageCopyTexture(texture, textureSpec.copyLevel, textureSpec.copyOrigin);
276         encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copySize);
277 
278         wgpu::CommandBuffer commands = encoder.Finish();
279         queue.Submit(1, &commands);
280 
281         const utils::TextureDataCopyLayout copyLayout =
282             utils::GetTextureDataCopyLayoutForTextureAtLevel(
283                 textureSpec.format, textureSpec.textureSize, textureSpec.copyLevel, dimension,
284                 bufferSpec.rowsPerImage);
285 
286         uint32_t copyLayer = copySize.depthOrArrayLayers;
287         uint32_t copyDepth = 1;
288         if (dimension == wgpu::TextureDimension::e3D) {
289             copyLayer = 1;
290             copyDepth = copySize.depthOrArrayLayers;
291         }
292 
293         uint64_t bufferOffset = bufferSpec.offset;
294         const uint32_t blockWidth = utils::GetTextureFormatBlockWidth(textureSpec.format);
295         const uint32_t blockHeight = utils::GetTextureFormatBlockHeight(textureSpec.format);
296         const uint32_t texelCountPerLayer = copyDepth * (copyLayout.mipSize.width / blockWidth) *
297                                             (copyLayout.mipSize.height / blockHeight) *
298                                             bytesPerTexel;
299         for (uint32_t layer = 0; layer < copyLayer; ++layer) {
300             // Copy and pack the data used to create the buffer in the specified copy region to have
301             // the same format as the expected texture data.
302             std::vector<RGBA8> expected(texelCountPerLayer);
303             CopyTextureData(bytesPerTexel, bufferData.data() + bufferOffset / bytesPerTexel,
304                             copySize.width, copySize.height, copyDepth, bufferSpec.bytesPerRow,
305                             bufferSpec.rowsPerImage, expected.data(),
306                             copySize.width * bytesPerTexel, copySize.height);
307 
308             EXPECT_TEXTURE_EQ(expected.data(), texture,
309                               {textureSpec.copyOrigin.x, textureSpec.copyOrigin.y,
310                                textureSpec.copyOrigin.z + layer},
311                               {copySize.width, copySize.height, copyDepth}, textureSpec.copyLevel)
312                 << "Buffer to Texture copy failed copying " << bufferSpec.size
313                 << "-byte buffer with offset " << bufferSpec.offset << " and bytes per row "
314                 << bufferSpec.bytesPerRow << " to [(" << textureSpec.copyOrigin.x << ", "
315                 << textureSpec.copyOrigin.y << "), (" << textureSpec.copyOrigin.x + copySize.width
316                 << ", " << textureSpec.copyOrigin.y + copySize.height << ")) region of "
317                 << textureSpec.textureSize.width << " x " << textureSpec.textureSize.height
318                 << " texture at mip level " << textureSpec.copyLevel << " layer " << layer
319                 << std::endl;
320             bufferOffset += copyLayout.bytesPerImage;
321         }
322     }
323 };
324 
325 namespace {
326     // The CopyTests Texture to Texture in this class will validate both CopyTextureToTexture and
327     // CopyTextureToTextureInternal.
328     using UsageCopySrc = bool;
329     DAWN_TEST_PARAM_STRUCT(CopyTestsParams, UsageCopySrc);
330 }  // namespace
331 
332 class CopyTests_T2T : public CopyTests, public DawnTestWithParams<CopyTestsParams> {
333   protected:
GetRequiredFeatures()334     std::vector<const char*> GetRequiredFeatures() override {
335         return {"dawn-internal-usages"};
336     }
337 
DoTest(const TextureSpec & srcSpec,const TextureSpec & dstSpec,const wgpu::Extent3D & copySize,bool copyWithinSameTexture=false,wgpu::TextureDimension dimension=wgpu::TextureDimension::e2D)338     void DoTest(const TextureSpec& srcSpec,
339                 const TextureSpec& dstSpec,
340                 const wgpu::Extent3D& copySize,
341                 bool copyWithinSameTexture = false,
342                 wgpu::TextureDimension dimension = wgpu::TextureDimension::e2D) {
343         DoTest(srcSpec, dstSpec, copySize, dimension, dimension, copyWithinSameTexture);
344     }
345 
DoTest(const TextureSpec & srcSpec,const TextureSpec & dstSpec,const wgpu::Extent3D & copySize,wgpu::TextureDimension srcDimension,wgpu::TextureDimension dstDimension,bool copyWithinSameTexture=false)346     void DoTest(const TextureSpec& srcSpec,
347                 const TextureSpec& dstSpec,
348                 const wgpu::Extent3D& copySize,
349                 wgpu::TextureDimension srcDimension,
350                 wgpu::TextureDimension dstDimension,
351                 bool copyWithinSameTexture = false) {
352         const bool usageCopySrc = GetParam().mUsageCopySrc;
353         // If we do this test with a CopyWithinSameTexture, it will need to have usageCopySrc in the
354         // public usage of the texture as it will later use a CopyTextureToBuffer, that needs the
355         // public usage of it.
356         DAWN_TEST_UNSUPPORTED_IF(!usageCopySrc && copyWithinSameTexture);
357 
358         ASSERT_EQ(srcSpec.format, dstSpec.format);
359         const wgpu::TextureFormat format = srcSpec.format;
360 
361         wgpu::TextureDescriptor srcDescriptor;
362         srcDescriptor.dimension = srcDimension;
363         srcDescriptor.size = srcSpec.textureSize;
364         srcDescriptor.sampleCount = 1;
365         srcDescriptor.format = format;
366         srcDescriptor.mipLevelCount = srcSpec.levelCount;
367         srcDescriptor.usage = wgpu::TextureUsage::CopyDst;
368         // This test will have two versions, one where we check the normal CopyToCopy, and for that
369         // we will add the CopySrc usage, and the one where we test the CopyToCopyInternal, and then
370         // we have to add the CopySrc to the Internal usage.
371         wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
372         srcDescriptor.nextInChain = &internalDesc;
373         if (usageCopySrc) {
374             srcDescriptor.usage |= wgpu::TextureUsage::CopySrc;
375         } else {
376             internalDesc.internalUsage = wgpu::TextureUsage::CopySrc;
377         }
378         wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
379 
380         wgpu::Texture dstTexture;
381         if (copyWithinSameTexture) {
382             dstTexture = srcTexture;
383         } else {
384             wgpu::TextureDescriptor dstDescriptor;
385             dstDescriptor.dimension = dstDimension;
386             dstDescriptor.size = dstSpec.textureSize;
387             dstDescriptor.sampleCount = 1;
388             dstDescriptor.format = format;
389             dstDescriptor.mipLevelCount = dstSpec.levelCount;
390             dstDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
391             dstTexture = device.CreateTexture(&dstDescriptor);
392         }
393 
394         // Create an upload buffer and use it to completely populate the subresources of the src
395         // texture that will be copied from at the given mip level.
396         const utils::TextureDataCopyLayout srcDataCopyLayout =
397             utils::GetTextureDataCopyLayoutForTextureAtLevel(
398                 format,
399                 {srcSpec.textureSize.width, srcSpec.textureSize.height,
400                  srcDimension == wgpu::TextureDimension::e3D
401                      ? srcSpec.textureSize.depthOrArrayLayers
402                      : copySize.depthOrArrayLayers},
403                 srcSpec.copyLevel, srcDimension);
404 
405         // Initialize the source texture
406         const std::vector<uint8_t> srcTextureCopyData = GetExpectedTextureData(srcDataCopyLayout);
407         {
408             wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
409                 srcTexture, srcSpec.copyLevel, {0, 0, srcSpec.copyOrigin.z});
410             wgpu::TextureDataLayout textureDataLayout = utils::CreateTextureDataLayout(
411                 0, srcDataCopyLayout.bytesPerRow, srcDataCopyLayout.rowsPerImage);
412             queue.WriteTexture(&imageCopyTexture, srcTextureCopyData.data(),
413                                srcDataCopyLayout.byteLength, &textureDataLayout,
414                                &srcDataCopyLayout.mipSize);
415         }
416 
417         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
418 
419         // Perform the texture to texture copy
420         wgpu::ImageCopyTexture srcImageCopyTexture =
421             utils::CreateImageCopyTexture(srcTexture, srcSpec.copyLevel, srcSpec.copyOrigin);
422         wgpu::ImageCopyTexture dstImageCopyTexture =
423             utils::CreateImageCopyTexture(dstTexture, dstSpec.copyLevel, dstSpec.copyOrigin);
424 
425         if (usageCopySrc) {
426             encoder.CopyTextureToTexture(&srcImageCopyTexture, &dstImageCopyTexture, &copySize);
427         } else {
428             encoder.CopyTextureToTextureInternal(&srcImageCopyTexture, &dstImageCopyTexture,
429                                                  &copySize);
430         }
431 
432         // Create an output buffer and use it to completely populate the subresources of the dst
433         // texture that will be copied to at the given mip level.
434         const utils::TextureDataCopyLayout dstDataCopyLayout =
435             utils::GetTextureDataCopyLayoutForTextureAtLevel(
436                 format,
437                 {dstSpec.textureSize.width, dstSpec.textureSize.height,
438                  dstDimension == wgpu::TextureDimension::e3D
439                      ? dstSpec.textureSize.depthOrArrayLayers
440                      : copySize.depthOrArrayLayers},
441                 dstSpec.copyLevel, dstDimension);
442         wgpu::BufferDescriptor outputBufferDescriptor;
443         outputBufferDescriptor.size = dstDataCopyLayout.byteLength;
444         outputBufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
445         wgpu::Buffer outputBuffer = device.CreateBuffer(&outputBufferDescriptor);
446         const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format);
447         const uint32_t expectedDstDataOffset = dstSpec.copyOrigin.x * bytesPerTexel +
448                                                dstSpec.copyOrigin.y * dstDataCopyLayout.bytesPerRow;
449         wgpu::ImageCopyBuffer outputImageCopyBuffer = utils::CreateImageCopyBuffer(
450             outputBuffer, expectedDstDataOffset, dstDataCopyLayout.bytesPerRow,
451             dstDataCopyLayout.rowsPerImage);
452         encoder.CopyTextureToBuffer(&dstImageCopyTexture, &outputImageCopyBuffer, &copySize);
453 
454         wgpu::CommandBuffer commands = encoder.Finish();
455         queue.Submit(1, &commands);
456 
457         // Validate if the data in outputBuffer is what we expected, including the untouched data
458         // outside of the copy.
459         {
460             // Validate the output buffer slice-by-slice regardless of whether the destination
461             // texture is 3D or 2D. The dimension here doesn't matter - we're only populating the
462             // CPU data to verify against.
463             uint32_t copyLayer = copySize.depthOrArrayLayers;
464             uint32_t copyDepth = 1;
465 
466             const uint64_t validDataSizePerDstTextureLayer = utils::RequiredBytesInCopy(
467                 dstDataCopyLayout.bytesPerRow, dstDataCopyLayout.mipSize.height,
468                 dstDataCopyLayout.mipSize.width, dstDataCopyLayout.mipSize.height, copyDepth,
469                 bytesPerTexel);
470 
471             // expectedDstDataPerSlice stores one layer of the destination texture.
472             std::vector<uint8_t> expectedDstDataPerSlice(validDataSizePerDstTextureLayer);
473             for (uint32_t slice = 0; slice < copyLayer; ++slice) {
474                 // For each source texture array slice involved in the copy, emulate the T2T copy
475                 // on the CPU side by "copying" the copy data from the "source texture"
476                 // (srcTextureCopyData) to the "destination texture" (expectedDstDataPerSlice).
477                 std::fill(expectedDstDataPerSlice.begin(), expectedDstDataPerSlice.end(), 0);
478 
479                 const uint32_t srcBytesOffset = srcDataCopyLayout.bytesPerImage * slice;
480 
481                 // Get the offset of the srcTextureCopyData that contains the copy data on the
482                 // slice-th texture array layer of the source texture.
483                 const uint32_t srcTexelDataOffset =
484                     srcBytesOffset + (srcSpec.copyOrigin.x * bytesPerTexel +
485                                       srcSpec.copyOrigin.y * srcDataCopyLayout.bytesPerRow);
486                 // Do the T2T "copy" on the CPU side to get the expected texel value at the
487                 CopyTextureData(bytesPerTexel, &srcTextureCopyData[srcTexelDataOffset],
488                                 copySize.width, copySize.height, copyDepth,
489                                 srcDataCopyLayout.bytesPerRow, srcDataCopyLayout.rowsPerImage,
490                                 &expectedDstDataPerSlice[expectedDstDataOffset],
491                                 dstDataCopyLayout.bytesPerRow, dstDataCopyLayout.rowsPerImage);
492 
493                 // Compare the content of the destination texture at the (dstSpec.copyOrigin.z +
494                 // slice)-th layer to its expected data after the copy (the outputBuffer contains
495                 // the data of the destination texture since the dstSpec.copyOrigin.z-th layer).
496                 uint64_t outputBufferExpectationBytesOffset =
497                     dstDataCopyLayout.bytesPerImage * slice;
498                 EXPECT_BUFFER_U32_RANGE_EQ(
499                     reinterpret_cast<const uint32_t*>(expectedDstDataPerSlice.data()), outputBuffer,
500                     outputBufferExpectationBytesOffset,
501                     validDataSizePerDstTextureLayer / sizeof(uint32_t));
502             }
503         }
504     }
505 };
506 
507 class CopyTests_B2B : public DawnTest {
508   protected:
509     // This is the same signature as CopyBufferToBuffer except that the buffers are replaced by
510     // only their size.
DoTest(uint64_t sourceSize,uint64_t sourceOffset,uint64_t destinationSize,uint64_t destinationOffset,uint64_t copySize)511     void DoTest(uint64_t sourceSize,
512                 uint64_t sourceOffset,
513                 uint64_t destinationSize,
514                 uint64_t destinationOffset,
515                 uint64_t copySize) {
516         ASSERT(sourceSize % 4 == 0);
517         ASSERT(destinationSize % 4 == 0);
518 
519         // Create our two test buffers, destination filled with zeros, source filled with non-zeroes
520         std::vector<uint32_t> zeroes(static_cast<size_t>(destinationSize / sizeof(uint32_t)));
521         wgpu::Buffer destination =
522             utils::CreateBufferFromData(device, zeroes.data(), zeroes.size() * sizeof(uint32_t),
523                                         wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc);
524 
525         std::vector<uint32_t> sourceData(static_cast<size_t>(sourceSize / sizeof(uint32_t)));
526         for (size_t i = 0; i < sourceData.size(); i++) {
527             sourceData[i] = i + 1;
528         }
529         wgpu::Buffer source = utils::CreateBufferFromData(device, sourceData.data(),
530                                                           sourceData.size() * sizeof(uint32_t),
531                                                           wgpu::BufferUsage::CopySrc);
532 
533         // Submit the copy
534         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
535         encoder.CopyBufferToBuffer(source, sourceOffset, destination, destinationOffset, copySize);
536         wgpu::CommandBuffer commands = encoder.Finish();
537         queue.Submit(1, &commands);
538 
539         // Check destination is exactly the expected content.
540         EXPECT_BUFFER_U32_RANGE_EQ(zeroes.data(), destination, 0,
541                                    destinationOffset / sizeof(uint32_t));
542         EXPECT_BUFFER_U32_RANGE_EQ(sourceData.data() + sourceOffset / sizeof(uint32_t), destination,
543                                    destinationOffset, copySize / sizeof(uint32_t));
544         uint64_t copyEnd = destinationOffset + copySize;
545         EXPECT_BUFFER_U32_RANGE_EQ(zeroes.data(), destination, copyEnd,
546                                    (destinationSize - copyEnd) / sizeof(uint32_t));
547     }
548 };
549 
550 class ClearBufferTests : public DawnTest {
551   protected:
552     // This is the same signature as ClearBuffer except that the buffers are replaced by
553     // only their size.
DoTest(uint64_t bufferSize,uint64_t clearOffset,uint64_t clearSize)554     void DoTest(uint64_t bufferSize, uint64_t clearOffset, uint64_t clearSize) {
555         ASSERT(bufferSize % 4 == 0);
556         ASSERT(clearSize % 4 == 0);
557 
558         // Create our test buffer, filled with non-zeroes
559         std::vector<uint32_t> bufferData(static_cast<size_t>(bufferSize / sizeof(uint32_t)));
560         for (size_t i = 0; i < bufferData.size(); i++) {
561             bufferData[i] = i + 1;
562         }
563         wgpu::Buffer buffer = utils::CreateBufferFromData(
564             device, bufferData.data(), bufferData.size() * sizeof(uint32_t),
565             wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc);
566 
567         std::vector<uint8_t> fillData(static_cast<size_t>(clearSize), 0u);
568 
569         // Submit the fill
570         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
571         encoder.ClearBuffer(buffer, clearOffset, clearSize);
572         wgpu::CommandBuffer commands = encoder.Finish();
573         queue.Submit(1, &commands);
574 
575         // Check destination is exactly the expected content.
576         EXPECT_BUFFER_U32_RANGE_EQ(bufferData.data(), buffer, 0, clearOffset / sizeof(uint32_t));
577         EXPECT_BUFFER_U8_RANGE_EQ(fillData.data(), buffer, clearOffset, clearSize);
578         uint64_t clearEnd = clearOffset + clearSize;
579         EXPECT_BUFFER_U32_RANGE_EQ(bufferData.data() + clearEnd / sizeof(uint32_t), buffer,
580                                    clearEnd, (bufferSize - clearEnd) / sizeof(uint32_t));
581     }
582 };
583 
584 // Test that copying an entire texture with 256-byte aligned dimensions works
TEST_P(CopyTests_T2B,FullTextureAligned)585 TEST_P(CopyTests_T2B, FullTextureAligned) {
586     constexpr uint32_t kWidth = 256;
587     constexpr uint32_t kHeight = 128;
588 
589     TextureSpec textureSpec;
590     textureSpec.textureSize = {kWidth, kHeight, 1};
591 
592     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 1});
593 }
594 
595 // Test noop copies
TEST_P(CopyTests_T2B,ZeroSizedCopy)596 TEST_P(CopyTests_T2B, ZeroSizedCopy) {
597     constexpr uint32_t kWidth = 256;
598     constexpr uint32_t kHeight = 128;
599 
600     TextureSpec textureSpec;
601     textureSpec.textureSize = {kWidth, kHeight, 1};
602 
603     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {0, kHeight, 1});
604     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, 0, 1});
605     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 0});
606 }
607 
608 // Test that copying an entire texture without 256-byte aligned dimensions works
TEST_P(CopyTests_T2B,FullTextureUnaligned)609 TEST_P(CopyTests_T2B, FullTextureUnaligned) {
610     constexpr uint32_t kWidth = 259;
611     constexpr uint32_t kHeight = 127;
612 
613     TextureSpec textureSpec;
614     textureSpec.textureSize = {kWidth, kHeight, 1};
615 
616     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 1});
617 }
618 
619 // Test that reading pixels from a 256-byte aligned texture works
TEST_P(CopyTests_T2B,PixelReadAligned)620 TEST_P(CopyTests_T2B, PixelReadAligned) {
621     constexpr uint32_t kWidth = 256;
622     constexpr uint32_t kHeight = 128;
623     BufferSpec pixelBuffer = MinimumBufferSpec(1, 1);
624 
625     constexpr wgpu::Extent3D kCopySize = {1, 1, 1};
626     constexpr wgpu::Extent3D kTextureSize = {kWidth, kHeight, 1};
627     TextureSpec defaultTextureSpec;
628     defaultTextureSpec.textureSize = kTextureSize;
629 
630     {
631         TextureSpec textureSpec = defaultTextureSpec;
632         DoTest(textureSpec, pixelBuffer, kCopySize);
633     }
634 
635     {
636         TextureSpec textureSpec = defaultTextureSpec;
637         textureSpec.copyOrigin = {kWidth - 1, 0, 0};
638         DoTest(textureSpec, pixelBuffer, kCopySize);
639     }
640 
641     {
642         TextureSpec textureSpec = defaultTextureSpec;
643         textureSpec.copyOrigin = {0, kHeight - 1, 0};
644         DoTest(textureSpec, pixelBuffer, kCopySize);
645     }
646 
647     {
648         TextureSpec textureSpec = defaultTextureSpec;
649         textureSpec.copyOrigin = {kWidth - 1, kHeight - 1, 0};
650         DoTest(textureSpec, pixelBuffer, kCopySize);
651     }
652 
653     {
654         TextureSpec textureSpec = defaultTextureSpec;
655         textureSpec.copyOrigin = {kWidth / 3, kHeight / 7, 0};
656         DoTest(textureSpec, pixelBuffer, kCopySize);
657     }
658 
659     {
660         TextureSpec textureSpec = defaultTextureSpec;
661         textureSpec.copyOrigin = {kWidth / 7, kHeight / 3, 0};
662         DoTest(textureSpec, pixelBuffer, kCopySize);
663     }
664 }
665 
666 // Test that copying pixels from a texture that is not 256-byte aligned works
TEST_P(CopyTests_T2B,PixelReadUnaligned)667 TEST_P(CopyTests_T2B, PixelReadUnaligned) {
668     constexpr uint32_t kWidth = 259;
669     constexpr uint32_t kHeight = 127;
670     BufferSpec pixelBuffer = MinimumBufferSpec(1, 1);
671 
672     constexpr wgpu::Extent3D kCopySize = {1, 1, 1};
673     constexpr wgpu::Extent3D kTextureSize = {kWidth, kHeight, 1};
674     TextureSpec defaultTextureSpec;
675     defaultTextureSpec.textureSize = kTextureSize;
676 
677     {
678         TextureSpec textureSpec = defaultTextureSpec;
679         DoTest(textureSpec, pixelBuffer, kCopySize);
680     }
681 
682     {
683         TextureSpec textureSpec = defaultTextureSpec;
684         textureSpec.copyOrigin = {kWidth - 1, 0, 0};
685         DoTest(textureSpec, pixelBuffer, kCopySize);
686     }
687 
688     {
689         TextureSpec textureSpec = defaultTextureSpec;
690         textureSpec.copyOrigin = {0, kHeight - 1, 0};
691         DoTest(textureSpec, pixelBuffer, kCopySize);
692     }
693 
694     {
695         TextureSpec textureSpec = defaultTextureSpec;
696         textureSpec.copyOrigin = {kWidth - 1, kHeight - 1, 0};
697         DoTest(textureSpec, pixelBuffer, kCopySize);
698     }
699 
700     {
701         TextureSpec textureSpec = defaultTextureSpec;
702         textureSpec.copyOrigin = {kWidth / 3, kHeight / 7, 0};
703         DoTest(textureSpec, pixelBuffer, kCopySize);
704     }
705 
706     {
707         TextureSpec textureSpec = defaultTextureSpec;
708         textureSpec.copyOrigin = {kWidth / 7, kHeight / 3, 0};
709         DoTest(textureSpec, pixelBuffer, kCopySize);
710     }
711 }
712 
713 // Test that copying regions with 256-byte aligned sizes works
TEST_P(CopyTests_T2B,TextureRegionAligned)714 TEST_P(CopyTests_T2B, TextureRegionAligned) {
715     constexpr uint32_t kWidth = 256;
716     constexpr uint32_t kHeight = 128;
717     for (unsigned int w : {64, 128, 256}) {
718         for (unsigned int h : {16, 32, 48}) {
719             TextureSpec textureSpec;
720             textureSpec.textureSize = {kWidth, kHeight, 1};
721             DoTest(textureSpec, MinimumBufferSpec(w, h), {w, h, 1});
722         }
723     }
724 }
725 
726 // Test that copying regions without 256-byte aligned sizes works
TEST_P(CopyTests_T2B,TextureRegionUnaligned)727 TEST_P(CopyTests_T2B, TextureRegionUnaligned) {
728     constexpr uint32_t kWidth = 256;
729     constexpr uint32_t kHeight = 128;
730 
731     TextureSpec defaultTextureSpec;
732     defaultTextureSpec.textureSize = {kWidth, kHeight, 1};
733 
734     for (unsigned int w : {13, 63, 65}) {
735         for (unsigned int h : {17, 19, 63}) {
736             TextureSpec textureSpec = defaultTextureSpec;
737             DoTest(textureSpec, MinimumBufferSpec(w, h), {w, h, 1});
738         }
739     }
740 }
741 
742 // Test that copying mips with 256-byte aligned sizes works
TEST_P(CopyTests_T2B,TextureMipAligned)743 TEST_P(CopyTests_T2B, TextureMipAligned) {
744     constexpr uint32_t kWidth = 256;
745     constexpr uint32_t kHeight = 128;
746 
747     TextureSpec defaultTextureSpec;
748     defaultTextureSpec.textureSize = {kWidth, kHeight, 1};
749 
750     for (unsigned int i = 1; i < 4; ++i) {
751         TextureSpec textureSpec = defaultTextureSpec;
752         textureSpec.copyLevel = i;
753         textureSpec.levelCount = i + 1;
754         DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i),
755                {kWidth >> i, kHeight >> i, 1});
756     }
757 }
758 
759 // Test that copying mips when one dimension is 256-byte aligned and another dimension reach one
760 // works
TEST_P(CopyTests_T2B,TextureMipDimensionReachOne)761 TEST_P(CopyTests_T2B, TextureMipDimensionReachOne) {
762     constexpr uint32_t mipLevelCount = 4;
763     constexpr uint32_t kWidth = 256 << mipLevelCount;
764     constexpr uint32_t kHeight = 2;
765 
766     TextureSpec defaultTextureSpec;
767     defaultTextureSpec.textureSize = {kWidth, kHeight, 1};
768 
769     TextureSpec textureSpec = defaultTextureSpec;
770     textureSpec.levelCount = mipLevelCount;
771 
772     for (unsigned int i = 0; i < 4; ++i) {
773         textureSpec.copyLevel = i;
774         DoTest(textureSpec,
775                MinimumBufferSpec(std::max(kWidth >> i, 1u), std::max(kHeight >> i, 1u)),
776                {std::max(kWidth >> i, 1u), std::max(kHeight >> i, 1u), 1});
777     }
778 }
779 
780 // Test that copying mips without 256-byte aligned sizes works
TEST_P(CopyTests_T2B,TextureMipUnaligned)781 TEST_P(CopyTests_T2B, TextureMipUnaligned) {
782     constexpr uint32_t kWidth = 259;
783     constexpr uint32_t kHeight = 127;
784 
785     TextureSpec defaultTextureSpec;
786     defaultTextureSpec.textureSize = {kWidth, kHeight, 1};
787 
788     for (unsigned int i = 1; i < 4; ++i) {
789         TextureSpec textureSpec = defaultTextureSpec;
790         textureSpec.copyLevel = i;
791         textureSpec.levelCount = i + 1;
792         DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i),
793                {kWidth >> i, kHeight >> i, 1});
794     }
795 }
796 
797 // Test that copying with a 512-byte aligned buffer offset works
TEST_P(CopyTests_T2B,OffsetBufferAligned)798 TEST_P(CopyTests_T2B, OffsetBufferAligned) {
799     constexpr uint32_t kWidth = 256;
800     constexpr uint32_t kHeight = 128;
801 
802     TextureSpec textureSpec;
803     textureSpec.textureSize = {kWidth, kHeight, 1};
804 
805     for (unsigned int i = 0; i < 3; ++i) {
806         BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
807         uint64_t offset = 512 * i;
808         bufferSpec.size += offset;
809         bufferSpec.offset += offset;
810         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1});
811     }
812 }
813 
814 // Test that copying without a 512-byte aligned buffer offset works
TEST_P(CopyTests_T2B,OffsetBufferUnaligned)815 TEST_P(CopyTests_T2B, OffsetBufferUnaligned) {
816     constexpr uint32_t kWidth = 128;
817     constexpr uint32_t kHeight = 128;
818 
819     TextureSpec textureSpec;
820     textureSpec.textureSize = {kWidth, kHeight, 1};
821 
822     const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(textureSpec.format);
823     for (uint32_t i = bytesPerTexel; i < 512; i += bytesPerTexel * 9) {
824         BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
825         bufferSpec.size += i;
826         bufferSpec.offset += i;
827         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1});
828     }
829 }
830 
831 // Test that copying without a 512-byte aligned buffer offset that is greater than the bytes per row
832 // works
TEST_P(CopyTests_T2B,OffsetBufferUnalignedSmallBytesPerRow)833 TEST_P(CopyTests_T2B, OffsetBufferUnalignedSmallBytesPerRow) {
834     constexpr uint32_t kWidth = 32;
835     constexpr uint32_t kHeight = 128;
836 
837     TextureSpec textureSpec;
838     textureSpec.textureSize = {kWidth, kHeight, 1};
839 
840     const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(textureSpec.format);
841     for (uint32_t i = 256 + bytesPerTexel; i < 512; i += bytesPerTexel * 9) {
842         BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
843         bufferSpec.size += i;
844         bufferSpec.offset += i;
845         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1});
846     }
847 }
848 
849 // Test that copying with a greater bytes per row than needed on a 256-byte aligned texture works
TEST_P(CopyTests_T2B,BytesPerRowAligned)850 TEST_P(CopyTests_T2B, BytesPerRowAligned) {
851     constexpr uint32_t kWidth = 256;
852     constexpr uint32_t kHeight = 128;
853 
854     TextureSpec textureSpec;
855     textureSpec.textureSize = {kWidth, kHeight, 1};
856 
857     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
858     for (unsigned int i = 1; i < 4; ++i) {
859         bufferSpec.bytesPerRow += 256;
860         bufferSpec.size += 256 * kHeight;
861         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1});
862     }
863 }
864 
865 // Test that copying with a greater bytes per row than needed on a texture that is not 256-byte
866 // aligned works
TEST_P(CopyTests_T2B,BytesPerRowUnaligned)867 TEST_P(CopyTests_T2B, BytesPerRowUnaligned) {
868     constexpr uint32_t kWidth = 259;
869     constexpr uint32_t kHeight = 127;
870 
871     TextureSpec textureSpec;
872     textureSpec.textureSize = {kWidth, kHeight, 1};
873 
874     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
875     for (unsigned int i = 1; i < 4; ++i) {
876         bufferSpec.bytesPerRow += 256;
877         bufferSpec.size += 256 * kHeight;
878         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1});
879     }
880 }
881 
882 // Test that copying with bytesPerRow = 0 and bytesPerRow < bytesInACompleteRow works
883 // when we're copying one row only
TEST_P(CopyTests_T2B,BytesPerRowWithOneRowCopy)884 TEST_P(CopyTests_T2B, BytesPerRowWithOneRowCopy) {
885     constexpr uint32_t kWidth = 259;
886     constexpr uint32_t kHeight = 127;
887 
888     TextureSpec textureSpec;
889     textureSpec.textureSize = {kWidth, kHeight, 1};
890 
891     {
892         BufferSpec bufferSpec = MinimumBufferSpec(5, 1);
893 
894         // bytesPerRow undefined
895         bufferSpec.bytesPerRow = wgpu::kCopyStrideUndefined;
896         DoTest(textureSpec, bufferSpec, {5, 1, 1});
897     }
898 }
899 
TEST_P(CopyTests_T2B,StrideSpecialCases)900 TEST_P(CopyTests_T2B, StrideSpecialCases) {
901     TextureSpec textureSpec;
902     textureSpec.textureSize = {4, 4, 4};
903 
904     // bytesPerRow 0
905     for (const wgpu::Extent3D copyExtent :
906          {wgpu::Extent3D{0, 2, 2}, {0, 0, 2}, {0, 2, 0}, {0, 0, 0}}) {
907         DoTest(textureSpec, MinimumBufferSpec(copyExtent, 0, 2), copyExtent);
908     }
909 
910     // bytesPerRow undefined
911     for (const wgpu::Extent3D copyExtent :
912          {wgpu::Extent3D{2, 1, 1}, {2, 0, 1}, {2, 1, 0}, {2, 0, 0}}) {
913         DoTest(textureSpec, MinimumBufferSpec(copyExtent, wgpu::kCopyStrideUndefined, 2),
914                copyExtent);
915     }
916 
917     // rowsPerImage 0
918     for (const wgpu::Extent3D copyExtent :
919          {wgpu::Extent3D{2, 0, 2}, {2, 0, 0}, {0, 0, 2}, {0, 0, 0}}) {
920         DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, 0), copyExtent);
921     }
922 
923     // rowsPerImage undefined
924     for (const wgpu::Extent3D copyExtent : {wgpu::Extent3D{2, 2, 1}, {2, 2, 0}}) {
925         DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, wgpu::kCopyStrideUndefined),
926                copyExtent);
927     }
928 }
929 
930 // Test copying a single slice with rowsPerImage larger than copy height and rowsPerImage will not
931 // take effect. If rowsPerImage takes effect, it looks like the copy may go past the end of the
932 // buffer.
TEST_P(CopyTests_T2B,RowsPerImageShouldNotCauseBufferOOBIfDepthOrArrayLayersIsOne)933 TEST_P(CopyTests_T2B, RowsPerImageShouldNotCauseBufferOOBIfDepthOrArrayLayersIsOne) {
934     // Check various offsets to cover each code path in the 2D split code in TextureCopySplitter.
935     for (uint32_t offset : {0, 4, 64}) {
936         constexpr uint32_t kWidth = 250;
937         constexpr uint32_t kHeight = 3;
938 
939         TextureSpec textureSpec;
940         textureSpec.textureSize = {kWidth, kHeight, 1};
941 
942         BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
943         bufferSpec.rowsPerImage = 2 * kHeight;
944         bufferSpec.offset = offset;
945         bufferSpec.size += offset;
946         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1});
947         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1}, wgpu::TextureDimension::e3D);
948     }
949 }
950 
951 // Test copying a single row with bytesPerRow larger than copy width and bytesPerRow will not
952 // take effect. If bytesPerRow takes effect, it looks like the copy may go past the end of the
953 // buffer.
TEST_P(CopyTests_T2B,BytesPerRowShouldNotCauseBufferOOBIfCopyHeightIsOne)954 TEST_P(CopyTests_T2B, BytesPerRowShouldNotCauseBufferOOBIfCopyHeightIsOne) {
955     // Check various offsets to cover each code path in the 2D split code in TextureCopySplitter.
956     for (uint32_t offset : {0, 4, 100}) {
957         constexpr uint32_t kWidth = 250;
958 
959         TextureSpec textureSpec;
960         textureSpec.textureSize = {kWidth, 1, 1};
961 
962         BufferSpec bufferSpec = MinimumBufferSpec(kWidth, 1);
963         bufferSpec.bytesPerRow = 1280;  // the default bytesPerRow is 1024.
964         bufferSpec.offset = offset;
965         bufferSpec.size += offset;
966         DoTest(textureSpec, bufferSpec, {kWidth, 1, 1});
967         DoTest(textureSpec, bufferSpec, {kWidth, 1, 1}, wgpu::TextureDimension::e3D);
968     }
969 }
970 
971 // A regression test for a bug on D3D12 backend that causes crash when doing texture-to-texture
972 // copy one row with the texture format Depth32Float.
TEST_P(CopyTests_T2B,CopyOneRowWithDepth32Float)973 TEST_P(CopyTests_T2B, CopyOneRowWithDepth32Float) {
974     // TODO(crbug.com/dawn/727): currently this test fails on many D3D12 drivers.
975     DAWN_SUPPRESS_TEST_IF(IsD3D12());
976 
977     constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::Depth32Float;
978     constexpr uint32_t kPixelsPerRow = 4u;
979 
980     wgpu::TextureDescriptor textureDescriptor;
981     textureDescriptor.format = kFormat;
982     textureDescriptor.size = {kPixelsPerRow, 1, 1};
983     textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment;
984     wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
985 
986     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
987 
988     // Initialize the depth texture with 0.5f.
989     constexpr float kClearDepthValue = 0.5f;
990     utils::ComboRenderPassDescriptor renderPass({}, texture.CreateView());
991     renderPass.cDepthStencilAttachmentInfo.clearDepth = kClearDepthValue;
992     renderPass.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Clear;
993     renderPass.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
994     wgpu::RenderPassEncoder renderPassEncoder = encoder.BeginRenderPass(&renderPass);
995     renderPassEncoder.EndPass();
996 
997     constexpr uint32_t kBufferCopyOffset = kTextureBytesPerRowAlignment;
998     const uint32_t kBufferSize =
999         kBufferCopyOffset + utils::GetTexelBlockSizeInBytes(kFormat) * kPixelsPerRow;
1000     wgpu::BufferDescriptor bufferDescriptor;
1001     bufferDescriptor.size = kBufferSize;
1002     bufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
1003     wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor);
1004 
1005     wgpu::ImageCopyBuffer imageCopyBuffer =
1006         utils::CreateImageCopyBuffer(buffer, kBufferCopyOffset, kTextureBytesPerRowAlignment);
1007     wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
1008 
1009     wgpu::Extent3D copySize = textureDescriptor.size;
1010     encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &copySize);
1011     wgpu::CommandBuffer commandBuffer = encoder.Finish();
1012     queue.Submit(1, &commandBuffer);
1013 
1014     std::array<float, kPixelsPerRow> expectedValues;
1015     std::fill(expectedValues.begin(), expectedValues.end(), kClearDepthValue);
1016     EXPECT_BUFFER_FLOAT_RANGE_EQ(expectedValues.data(), buffer, kBufferCopyOffset, kPixelsPerRow);
1017 }
1018 
1019 // Test that copying whole texture 2D array layers in one texture-to-buffer-copy works.
TEST_P(CopyTests_T2B,Texture2DArrayFull)1020 TEST_P(CopyTests_T2B, Texture2DArrayFull) {
1021     constexpr uint32_t kWidth = 256;
1022     constexpr uint32_t kHeight = 128;
1023     constexpr uint32_t kLayers = 6u;
1024 
1025     TextureSpec textureSpec;
1026     textureSpec.textureSize = {kWidth, kHeight, kLayers};
1027 
1028     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kLayers), {kWidth, kHeight, kLayers});
1029 }
1030 
1031 // Test that copying a range of texture 2D array layers in one texture-to-buffer-copy works.
TEST_P(CopyTests_T2B,Texture2DArraySubRegion)1032 TEST_P(CopyTests_T2B, Texture2DArraySubRegion) {
1033     constexpr uint32_t kWidth = 256;
1034     constexpr uint32_t kHeight = 128;
1035     constexpr uint32_t kLayers = 6u;
1036     constexpr uint32_t kBaseLayer = 2u;
1037     constexpr uint32_t kCopyLayers = 3u;
1038 
1039     TextureSpec textureSpec;
1040     textureSpec.copyOrigin = {0, 0, kBaseLayer};
1041     textureSpec.textureSize = {kWidth, kHeight, kLayers};
1042 
1043     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kCopyLayers),
1044            {kWidth, kHeight, kCopyLayers});
1045 }
1046 
1047 // Test that copying texture 2D array mips with 256-byte aligned sizes works
TEST_P(CopyTests_T2B,Texture2DArrayMip)1048 TEST_P(CopyTests_T2B, Texture2DArrayMip) {
1049     constexpr uint32_t kWidth = 256;
1050     constexpr uint32_t kHeight = 128;
1051     constexpr uint32_t kLayers = 6u;
1052 
1053     TextureSpec defaultTextureSpec;
1054     defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers};
1055 
1056     for (unsigned int i = 1; i < 4; ++i) {
1057         TextureSpec textureSpec = defaultTextureSpec;
1058         textureSpec.copyLevel = i;
1059         textureSpec.levelCount = i + 1;
1060 
1061         DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i, kLayers),
1062                {kWidth >> i, kHeight >> i, kLayers});
1063     }
1064 }
1065 
1066 // Test that copying from a range of texture 2D array layers in one texture-to-buffer-copy when
1067 // RowsPerImage is not equal to the height of the texture works.
TEST_P(CopyTests_T2B,Texture2DArrayRegionNonzeroRowsPerImage)1068 TEST_P(CopyTests_T2B, Texture2DArrayRegionNonzeroRowsPerImage) {
1069     constexpr uint32_t kWidth = 256;
1070     constexpr uint32_t kHeight = 128;
1071     constexpr uint32_t kLayers = 6u;
1072     constexpr uint32_t kBaseLayer = 2u;
1073     constexpr uint32_t kCopyLayers = 3u;
1074 
1075     constexpr uint32_t kRowsPerImage = kHeight * 2;
1076 
1077     TextureSpec textureSpec;
1078     textureSpec.copyOrigin = {0, 0, kBaseLayer};
1079     textureSpec.textureSize = {kWidth, kHeight, kLayers};
1080 
1081     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
1082     bufferSpec.rowsPerImage = kRowsPerImage;
1083     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers});
1084 }
1085 
1086 // Test a special code path in the D3D12 backends when (BytesPerRow * RowsPerImage) is not a
1087 // multiple of 512.
TEST_P(CopyTests_T2B,Texture2DArrayRegionWithOffsetOddRowsPerImage)1088 TEST_P(CopyTests_T2B, Texture2DArrayRegionWithOffsetOddRowsPerImage) {
1089     constexpr uint32_t kWidth = 64;
1090     constexpr uint32_t kHeight = 128;
1091     constexpr uint32_t kLayers = 8u;
1092     constexpr uint32_t kBaseLayer = 2u;
1093     constexpr uint32_t kCopyLayers = 5u;
1094 
1095     constexpr uint32_t kRowsPerImage = kHeight + 1;
1096 
1097     TextureSpec textureSpec;
1098     textureSpec.copyOrigin = {0, 0, kBaseLayer};
1099     textureSpec.textureSize = {kWidth, kHeight, kLayers};
1100 
1101     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
1102     bufferSpec.offset += 128u;
1103     bufferSpec.size += 128u;
1104     bufferSpec.rowsPerImage = kRowsPerImage;
1105     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers});
1106 }
1107 
1108 // Test a special code path in the D3D12 backends when (BytesPerRow * RowsPerImage) is a multiple
1109 // of 512.
TEST_P(CopyTests_T2B,Texture2DArrayRegionWithOffsetEvenRowsPerImage)1110 TEST_P(CopyTests_T2B, Texture2DArrayRegionWithOffsetEvenRowsPerImage) {
1111     constexpr uint32_t kWidth = 64;
1112     constexpr uint32_t kHeight = 128;
1113     constexpr uint32_t kLayers = 8u;
1114     constexpr uint32_t kBaseLayer = 2u;
1115     constexpr uint32_t kCopyLayers = 4u;
1116 
1117     constexpr uint32_t kRowsPerImage = kHeight + 2;
1118 
1119     TextureSpec textureSpec;
1120     textureSpec.copyOrigin = {0, 0, kBaseLayer};
1121     textureSpec.textureSize = {kWidth, kHeight, kLayers};
1122 
1123     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
1124     bufferSpec.offset += 128u;
1125     bufferSpec.size += 128u;
1126     bufferSpec.rowsPerImage = kRowsPerImage;
1127     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers});
1128 }
1129 
1130 // Test that copying whole 3D texture in one texture-to-buffer-copy works.
TEST_P(CopyTests_T2B,Texture3DFull)1131 TEST_P(CopyTests_T2B, Texture3DFull) {
1132     constexpr uint32_t kWidth = 256;
1133     constexpr uint32_t kHeight = 128;
1134     constexpr uint32_t kDepth = 6;
1135 
1136     TextureSpec textureSpec;
1137     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1138 
1139     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kDepth), {kWidth, kHeight, kDepth},
1140            wgpu::TextureDimension::e3D);
1141 }
1142 
1143 // Test that copying a range of texture 3D depths in one texture-to-buffer-copy works.
TEST_P(CopyTests_T2B,Texture3DSubRegion)1144 TEST_P(CopyTests_T2B, Texture3DSubRegion) {
1145     DAWN_TEST_UNSUPPORTED_IF(IsANGLE());  // TODO(crbug.com/angleproject/5967)
1146 
1147     constexpr uint32_t kWidth = 256;
1148     constexpr uint32_t kHeight = 128;
1149     constexpr uint32_t kDepth = 6;
1150     constexpr uint32_t kBaseDepth = 2u;
1151     constexpr uint32_t kCopyDepth = 3u;
1152 
1153     TextureSpec textureSpec;
1154     textureSpec.copyOrigin = {0, 0, kBaseDepth};
1155     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1156 
1157     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kCopyDepth),
1158            {kWidth / 2, kHeight / 2, kCopyDepth}, wgpu::TextureDimension::e3D);
1159 }
1160 
TEST_P(CopyTests_T2B,Texture3DNoSplitRowDataWithEmptyFirstRow)1161 TEST_P(CopyTests_T2B, Texture3DNoSplitRowDataWithEmptyFirstRow) {
1162     constexpr uint32_t kWidth = 2;
1163     constexpr uint32_t kHeight = 4;
1164     constexpr uint32_t kDepth = 3;
1165 
1166     TextureSpec textureSpec;
1167     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1168     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight, kDepth);
1169 
1170     // The tests below are designed to test TextureCopySplitter for 3D textures on D3D12.
1171     // Base: no split for a row + no empty first row
1172     bufferSpec.offset = 60;
1173     bufferSpec.size += bufferSpec.offset;
1174     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1175 
1176     // This test will cover: no split for a row + empty first row
1177     bufferSpec.offset = 260;
1178     bufferSpec.size += bufferSpec.offset;
1179     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1180 }
1181 
TEST_P(CopyTests_T2B,Texture3DSplitRowDataWithoutEmptyFirstRow)1182 TEST_P(CopyTests_T2B, Texture3DSplitRowDataWithoutEmptyFirstRow) {
1183     constexpr uint32_t kWidth = 259;
1184     constexpr uint32_t kHeight = 127;
1185     constexpr uint32_t kDepth = 3;
1186 
1187     TextureSpec textureSpec;
1188     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1189     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight, kDepth);
1190 
1191     // The test below is designed to test TextureCopySplitter for 3D textures on D3D12.
1192     // This test will cover: split for a row + no empty first row for both split regions
1193     bufferSpec.offset = 260;
1194     bufferSpec.size += bufferSpec.offset;
1195     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1196 }
1197 
TEST_P(CopyTests_T2B,Texture3DSplitRowDataWithEmptyFirstRow)1198 TEST_P(CopyTests_T2B, Texture3DSplitRowDataWithEmptyFirstRow) {
1199     constexpr uint32_t kWidth = 39;
1200     constexpr uint32_t kHeight = 4;
1201     constexpr uint32_t kDepth = 3;
1202 
1203     TextureSpec textureSpec;
1204     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1205     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight, kDepth);
1206 
1207     // The tests below are designed to test TextureCopySplitter for 3D textures on D3D12.
1208     // This test will cover: split for a row + empty first row for the head block
1209     bufferSpec.offset = 400;
1210     bufferSpec.size += bufferSpec.offset;
1211     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1212 
1213     // This test will cover: split for a row + empty first row for the tail block
1214     bufferSpec.offset = 160;
1215     bufferSpec.size += bufferSpec.offset;
1216     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1217 }
1218 
TEST_P(CopyTests_T2B,Texture3DCopyHeightIsOneCopyWidthIsTiny)1219 TEST_P(CopyTests_T2B, Texture3DCopyHeightIsOneCopyWidthIsTiny) {
1220     constexpr uint32_t kWidth = 2;
1221     constexpr uint32_t kHeight = 1;
1222     constexpr uint32_t kDepth = 3;
1223 
1224     TextureSpec textureSpec;
1225     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1226     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight, kDepth);
1227 
1228     // The tests below are designed to test TextureCopySplitter for 3D textures on D3D12.
1229     // Base: no split for a row, no empty row, and copy height is 1
1230     bufferSpec.offset = 60;
1231     bufferSpec.size += bufferSpec.offset;
1232     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1233 
1234     // This test will cover: no split for a row + empty first row, and copy height is 1
1235     bufferSpec.offset = 260;
1236     bufferSpec.size += bufferSpec.offset;
1237     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1238 }
1239 
TEST_P(CopyTests_T2B,Texture3DCopyHeightIsOneCopyWidthIsSmall)1240 TEST_P(CopyTests_T2B, Texture3DCopyHeightIsOneCopyWidthIsSmall) {
1241     constexpr uint32_t kWidth = 39;
1242     constexpr uint32_t kHeight = 1;
1243     constexpr uint32_t kDepth = 3;
1244 
1245     TextureSpec textureSpec;
1246     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1247     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight, kDepth);
1248 
1249     // The tests below are designed to test TextureCopySplitter for 3D textures on D3D12.
1250     // This test will cover: split for a row + empty first row for the head block, and copy height
1251     // is 1
1252     bufferSpec.offset = 400;
1253     bufferSpec.size += bufferSpec.offset;
1254     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1255 
1256     // This test will cover: split for a row + empty first row for the tail block, and copy height
1257     // is 1
1258     bufferSpec.offset = 160;
1259     bufferSpec.size += bufferSpec.offset;
1260     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1261 }
1262 
1263 // Test that copying texture 3D array mips with 256-byte aligned sizes works
TEST_P(CopyTests_T2B,Texture3DMipAligned)1264 TEST_P(CopyTests_T2B, Texture3DMipAligned) {
1265     constexpr uint32_t kWidth = 256;
1266     constexpr uint32_t kHeight = 128;
1267     constexpr uint32_t kDepth = 64u;
1268 
1269     TextureSpec defaultTextureSpec;
1270     defaultTextureSpec.textureSize = {kWidth, kHeight, kDepth};
1271 
1272     for (unsigned int i = 1; i < 6; ++i) {
1273         TextureSpec textureSpec = defaultTextureSpec;
1274         textureSpec.copyLevel = i;
1275         textureSpec.levelCount = i + 1;
1276 
1277         DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i, kDepth >> i),
1278                {kWidth >> i, kHeight >> i, kDepth >> i}, wgpu::TextureDimension::e3D);
1279     }
1280 }
1281 
1282 // Test that copying texture 3D array mips with 256-byte unaligned sizes works
TEST_P(CopyTests_T2B,Texture3DMipUnaligned)1283 TEST_P(CopyTests_T2B, Texture3DMipUnaligned) {
1284     constexpr uint32_t kWidth = 261;
1285     constexpr uint32_t kHeight = 123;
1286     constexpr uint32_t kDepth = 69u;
1287 
1288     TextureSpec defaultTextureSpec;
1289     defaultTextureSpec.textureSize = {kWidth, kHeight, kDepth};
1290 
1291     for (unsigned int i = 1; i < 6; ++i) {
1292         TextureSpec textureSpec = defaultTextureSpec;
1293         textureSpec.copyLevel = i;
1294         textureSpec.levelCount = i + 1;
1295 
1296         DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i, kDepth >> i),
1297                {kWidth >> i, kHeight >> i, kDepth >> i}, wgpu::TextureDimension::e3D);
1298     }
1299 }
1300 
1301 DAWN_INSTANTIATE_TEST(CopyTests_T2B,
1302                       D3D12Backend(),
1303                       MetalBackend(),
1304                       OpenGLBackend(),
1305                       OpenGLESBackend(),
1306                       VulkanBackend());
1307 
1308 // Test that copying an entire texture with 256-byte aligned dimensions works
TEST_P(CopyTests_B2T,FullTextureAligned)1309 TEST_P(CopyTests_B2T, FullTextureAligned) {
1310     constexpr uint32_t kWidth = 256;
1311     constexpr uint32_t kHeight = 128;
1312 
1313     TextureSpec textureSpec;
1314     textureSpec.textureSize = {kWidth, kHeight, 1};
1315 
1316     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 1});
1317 }
1318 
1319 // Test noop copies.
TEST_P(CopyTests_B2T,ZeroSizedCopy)1320 TEST_P(CopyTests_B2T, ZeroSizedCopy) {
1321     constexpr uint32_t kWidth = 256;
1322     constexpr uint32_t kHeight = 128;
1323 
1324     TextureSpec textureSpec;
1325     textureSpec.textureSize = {kWidth, kHeight, 1};
1326 
1327     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {0, kHeight, 1});
1328     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, 0, 1});
1329     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 0});
1330 }
1331 
1332 // Test that copying an entire texture without 256-byte aligned dimensions works
TEST_P(CopyTests_B2T,FullTextureUnaligned)1333 TEST_P(CopyTests_B2T, FullTextureUnaligned) {
1334     constexpr uint32_t kWidth = 259;
1335     constexpr uint32_t kHeight = 127;
1336 
1337     TextureSpec textureSpec;
1338     textureSpec.textureSize = {kWidth, kHeight, 1};
1339 
1340     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 1});
1341 }
1342 
1343 // Test that reading pixels from a 256-byte aligned texture works
TEST_P(CopyTests_B2T,PixelReadAligned)1344 TEST_P(CopyTests_B2T, PixelReadAligned) {
1345     constexpr uint32_t kWidth = 256;
1346     constexpr uint32_t kHeight = 128;
1347     BufferSpec pixelBuffer = MinimumBufferSpec(1, 1);
1348 
1349     constexpr wgpu::Extent3D kCopySize = {1, 1, 1};
1350     constexpr wgpu::Extent3D kTextureSize = {kWidth, kHeight, 1};
1351     TextureSpec defaultTextureSpec;
1352     defaultTextureSpec.textureSize = kTextureSize;
1353 
1354     {
1355         TextureSpec textureSpec = defaultTextureSpec;
1356         DoTest(textureSpec, pixelBuffer, kCopySize);
1357     }
1358 
1359     {
1360         TextureSpec textureSpec = defaultTextureSpec;
1361         textureSpec.copyOrigin = {kWidth - 1, 0, 0};
1362         DoTest(textureSpec, pixelBuffer, kCopySize);
1363     }
1364 
1365     {
1366         TextureSpec textureSpec = defaultTextureSpec;
1367         textureSpec.copyOrigin = {0, kHeight - 1, 0};
1368         DoTest(textureSpec, pixelBuffer, kCopySize);
1369     }
1370 
1371     {
1372         TextureSpec textureSpec = defaultTextureSpec;
1373         textureSpec.copyOrigin = {kWidth - 1, kHeight - 1, 0};
1374         DoTest(textureSpec, pixelBuffer, kCopySize);
1375     }
1376 
1377     {
1378         TextureSpec textureSpec = defaultTextureSpec;
1379         textureSpec.copyOrigin = {kWidth / 3, kHeight / 7, 0};
1380         DoTest(textureSpec, pixelBuffer, kCopySize);
1381     }
1382 
1383     {
1384         TextureSpec textureSpec = defaultTextureSpec;
1385         textureSpec.copyOrigin = {kWidth / 7, kHeight / 3, 0};
1386         DoTest(textureSpec, pixelBuffer, kCopySize);
1387     }
1388 }
1389 
1390 // Test that copying pixels from a texture that is not 256-byte aligned works
TEST_P(CopyTests_B2T,PixelReadUnaligned)1391 TEST_P(CopyTests_B2T, PixelReadUnaligned) {
1392     constexpr uint32_t kWidth = 259;
1393     constexpr uint32_t kHeight = 127;
1394     BufferSpec pixelBuffer = MinimumBufferSpec(1, 1);
1395 
1396     constexpr wgpu::Extent3D kCopySize = {1, 1, 1};
1397     constexpr wgpu::Extent3D kTextureSize = {kWidth, kHeight, 1};
1398     TextureSpec defaultTextureSpec;
1399     defaultTextureSpec.textureSize = kTextureSize;
1400 
1401     {
1402         TextureSpec textureSpec = defaultTextureSpec;
1403         DoTest(textureSpec, pixelBuffer, kCopySize);
1404     }
1405 
1406     {
1407         TextureSpec textureSpec = defaultTextureSpec;
1408         textureSpec.copyOrigin = {kWidth - 1, 0, 0};
1409         DoTest(textureSpec, pixelBuffer, kCopySize);
1410     }
1411 
1412     {
1413         TextureSpec textureSpec = defaultTextureSpec;
1414         textureSpec.copyOrigin = {0, kHeight - 1, 0};
1415         DoTest(textureSpec, pixelBuffer, kCopySize);
1416     }
1417 
1418     {
1419         TextureSpec textureSpec = defaultTextureSpec;
1420         textureSpec.copyOrigin = {kWidth - 1, kHeight - 1, 0};
1421         DoTest(textureSpec, pixelBuffer, kCopySize);
1422     }
1423 
1424     {
1425         TextureSpec textureSpec = defaultTextureSpec;
1426         textureSpec.copyOrigin = {kWidth / 3, kHeight / 7, 0};
1427         DoTest(textureSpec, pixelBuffer, kCopySize);
1428     }
1429 
1430     {
1431         TextureSpec textureSpec = defaultTextureSpec;
1432         textureSpec.copyOrigin = {kWidth / 7, kHeight / 3, 0};
1433         DoTest(textureSpec, pixelBuffer, kCopySize);
1434     }
1435 }
1436 
1437 // Test that copying regions with 256-byte aligned sizes works
TEST_P(CopyTests_B2T,TextureRegionAligned)1438 TEST_P(CopyTests_B2T, TextureRegionAligned) {
1439     constexpr uint32_t kWidth = 256;
1440     constexpr uint32_t kHeight = 128;
1441     for (unsigned int w : {64, 128, 256}) {
1442         for (unsigned int h : {16, 32, 48}) {
1443             TextureSpec textureSpec;
1444             textureSpec.textureSize = {kWidth, kHeight, 1};
1445             DoTest(textureSpec, MinimumBufferSpec(w, h), {w, h, 1});
1446         }
1447     }
1448 }
1449 
1450 // Test that copying regions without 256-byte aligned sizes works
TEST_P(CopyTests_B2T,TextureRegionUnaligned)1451 TEST_P(CopyTests_B2T, TextureRegionUnaligned) {
1452     constexpr uint32_t kWidth = 256;
1453     constexpr uint32_t kHeight = 128;
1454 
1455     TextureSpec defaultTextureSpec;
1456     defaultTextureSpec.textureSize = {kWidth, kHeight, 1};
1457 
1458     for (unsigned int w : {13, 63, 65}) {
1459         for (unsigned int h : {17, 19, 63}) {
1460             TextureSpec textureSpec = defaultTextureSpec;
1461             DoTest(textureSpec, MinimumBufferSpec(w, h), {w, h, 1});
1462         }
1463     }
1464 }
1465 
1466 // Test that copying mips with 256-byte aligned sizes works
TEST_P(CopyTests_B2T,TextureMipAligned)1467 TEST_P(CopyTests_B2T, TextureMipAligned) {
1468     constexpr uint32_t kWidth = 256;
1469     constexpr uint32_t kHeight = 128;
1470 
1471     TextureSpec defaultTextureSpec;
1472     defaultTextureSpec.textureSize = {kWidth, kHeight, 1};
1473 
1474     for (unsigned int i = 1; i < 4; ++i) {
1475         TextureSpec textureSpec = defaultTextureSpec;
1476         textureSpec.copyLevel = i;
1477         textureSpec.levelCount = i + 1;
1478         DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i),
1479                {kWidth >> i, kHeight >> i, 1});
1480     }
1481 }
1482 
1483 // Test that copying mips without 256-byte aligned sizes works
TEST_P(CopyTests_B2T,TextureMipUnaligned)1484 TEST_P(CopyTests_B2T, TextureMipUnaligned) {
1485     constexpr uint32_t kWidth = 259;
1486     constexpr uint32_t kHeight = 127;
1487 
1488     TextureSpec defaultTextureSpec;
1489     defaultTextureSpec.textureSize = {kWidth, kHeight, 1};
1490 
1491     for (unsigned int i = 1; i < 4; ++i) {
1492         TextureSpec textureSpec = defaultTextureSpec;
1493         textureSpec.copyLevel = i;
1494         textureSpec.levelCount = i + 1;
1495         DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i),
1496                {kWidth >> i, kHeight >> i, 1});
1497     }
1498 }
1499 
1500 // Test that copying with a 512-byte aligned buffer offset works
TEST_P(CopyTests_B2T,OffsetBufferAligned)1501 TEST_P(CopyTests_B2T, OffsetBufferAligned) {
1502     constexpr uint32_t kWidth = 256;
1503     constexpr uint32_t kHeight = 128;
1504 
1505     TextureSpec textureSpec;
1506     textureSpec.textureSize = {kWidth, kHeight, 1};
1507 
1508     for (unsigned int i = 0; i < 3; ++i) {
1509         BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
1510         uint64_t offset = 512 * i;
1511         bufferSpec.size += offset;
1512         bufferSpec.offset += offset;
1513         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1});
1514     }
1515 }
1516 
1517 // Test that copying without a 512-byte aligned buffer offset works
TEST_P(CopyTests_B2T,OffsetBufferUnaligned)1518 TEST_P(CopyTests_B2T, OffsetBufferUnaligned) {
1519     constexpr uint32_t kWidth = 256;
1520     constexpr uint32_t kHeight = 128;
1521 
1522     TextureSpec textureSpec;
1523     textureSpec.textureSize = {kWidth, kHeight, 1};
1524 
1525     const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(textureSpec.format);
1526     for (uint32_t i = bytesPerTexel; i < 512; i += bytesPerTexel * 9) {
1527         BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
1528         bufferSpec.size += i;
1529         bufferSpec.offset += i;
1530         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1});
1531     }
1532 }
1533 
1534 // Test that copying without a 512-byte aligned buffer offset that is greater than the bytes per row
1535 // works
TEST_P(CopyTests_B2T,OffsetBufferUnalignedSmallBytesPerRow)1536 TEST_P(CopyTests_B2T, OffsetBufferUnalignedSmallBytesPerRow) {
1537     constexpr uint32_t kWidth = 32;
1538     constexpr uint32_t kHeight = 128;
1539 
1540     TextureSpec textureSpec;
1541     textureSpec.textureSize = {kWidth, kHeight, 1};
1542 
1543     const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(textureSpec.format);
1544     for (uint32_t i = 256 + bytesPerTexel; i < 512; i += bytesPerTexel * 9) {
1545         BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
1546         bufferSpec.size += i;
1547         bufferSpec.offset += i;
1548         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1});
1549     }
1550 }
1551 
1552 // Test that copying with a greater bytes per row than needed on a 256-byte aligned texture works
TEST_P(CopyTests_B2T,BytesPerRowAligned)1553 TEST_P(CopyTests_B2T, BytesPerRowAligned) {
1554     constexpr uint32_t kWidth = 256;
1555     constexpr uint32_t kHeight = 128;
1556 
1557     TextureSpec textureSpec;
1558     textureSpec.textureSize = {kWidth, kHeight, 1};
1559 
1560     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
1561     for (unsigned int i = 1; i < 4; ++i) {
1562         bufferSpec.bytesPerRow += 256;
1563         bufferSpec.size += 256 * kHeight;
1564         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1});
1565     }
1566 }
1567 
1568 // Test that copying with a greater bytes per row than needed on a texture that is not 256-byte
1569 // aligned works
TEST_P(CopyTests_B2T,BytesPerRowUnaligned)1570 TEST_P(CopyTests_B2T, BytesPerRowUnaligned) {
1571     constexpr uint32_t kWidth = 259;
1572     constexpr uint32_t kHeight = 127;
1573 
1574     TextureSpec textureSpec;
1575     textureSpec.textureSize = {kWidth, kHeight, 1};
1576 
1577     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
1578     for (unsigned int i = 1; i < 4; ++i) {
1579         bufferSpec.bytesPerRow += 256;
1580         bufferSpec.size += 256 * kHeight;
1581         DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1});
1582     }
1583 }
1584 
1585 // Test that copying with bytesPerRow = 0 and bytesPerRow < bytesInACompleteRow works
1586 // when we're copying one row only
TEST_P(CopyTests_B2T,BytesPerRowWithOneRowCopy)1587 TEST_P(CopyTests_B2T, BytesPerRowWithOneRowCopy) {
1588     constexpr uint32_t kWidth = 259;
1589     constexpr uint32_t kHeight = 127;
1590 
1591     TextureSpec textureSpec;
1592     textureSpec.textureSize = {kWidth, kHeight, 1};
1593 
1594     {
1595         BufferSpec bufferSpec = MinimumBufferSpec(5, 1);
1596 
1597         // bytesPerRow undefined
1598         bufferSpec.bytesPerRow = wgpu::kCopyStrideUndefined;
1599         DoTest(textureSpec, bufferSpec, {5, 1, 1});
1600     }
1601 }
1602 
TEST_P(CopyTests_B2T,StrideSpecialCases)1603 TEST_P(CopyTests_B2T, StrideSpecialCases) {
1604     TextureSpec textureSpec;
1605     textureSpec.textureSize = {4, 4, 4};
1606 
1607     // bytesPerRow 0
1608     for (const wgpu::Extent3D copyExtent :
1609          {wgpu::Extent3D{0, 2, 2}, {0, 0, 2}, {0, 2, 0}, {0, 0, 0}}) {
1610         DoTest(textureSpec, MinimumBufferSpec(copyExtent, 0, 2), copyExtent);
1611     }
1612 
1613     // bytesPerRow undefined
1614     for (const wgpu::Extent3D copyExtent :
1615          {wgpu::Extent3D{2, 1, 1}, {2, 0, 1}, {2, 1, 0}, {2, 0, 0}}) {
1616         DoTest(textureSpec, MinimumBufferSpec(copyExtent, wgpu::kCopyStrideUndefined, 2),
1617                copyExtent);
1618     }
1619 
1620     // rowsPerImage 0
1621     for (const wgpu::Extent3D copyExtent :
1622          {wgpu::Extent3D{2, 0, 2}, {2, 0, 0}, {0, 0, 2}, {0, 0, 0}}) {
1623         DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, 0), copyExtent);
1624     }
1625 
1626     // rowsPerImage undefined
1627     for (const wgpu::Extent3D copyExtent : {wgpu::Extent3D{2, 2, 1}, {2, 2, 0}}) {
1628         DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, wgpu::kCopyStrideUndefined),
1629                copyExtent);
1630     }
1631 }
1632 
1633 // Test that copying whole texture 2D array layers in one texture-to-buffer-copy works.
TEST_P(CopyTests_B2T,Texture2DArrayFull)1634 TEST_P(CopyTests_B2T, Texture2DArrayFull) {
1635     constexpr uint32_t kWidth = 256;
1636     constexpr uint32_t kHeight = 128;
1637     constexpr uint32_t kLayers = 6u;
1638 
1639     TextureSpec textureSpec;
1640     textureSpec.textureSize = {kWidth, kHeight, kLayers};
1641 
1642     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kLayers), {kWidth, kHeight, kLayers});
1643 }
1644 
1645 // Test that copying a range of texture 2D array layers in one texture-to-buffer-copy works.
TEST_P(CopyTests_B2T,Texture2DArraySubRegion)1646 TEST_P(CopyTests_B2T, Texture2DArraySubRegion) {
1647     constexpr uint32_t kWidth = 256;
1648     constexpr uint32_t kHeight = 128;
1649     constexpr uint32_t kLayers = 6u;
1650     constexpr uint32_t kBaseLayer = 2u;
1651     constexpr uint32_t kCopyLayers = 3u;
1652 
1653     TextureSpec textureSpec;
1654     textureSpec.copyOrigin = {0, 0, kBaseLayer};
1655     textureSpec.textureSize = {kWidth, kHeight, kLayers};
1656 
1657     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kCopyLayers),
1658            {kWidth, kHeight, kCopyLayers});
1659 }
1660 
1661 // Test that copying into a range of texture 2D array layers in one texture-to-buffer-copy when
1662 // RowsPerImage is not equal to the height of the texture works.
TEST_P(CopyTests_B2T,Texture2DArrayRegionNonzeroRowsPerImage)1663 TEST_P(CopyTests_B2T, Texture2DArrayRegionNonzeroRowsPerImage) {
1664     constexpr uint32_t kWidth = 256;
1665     constexpr uint32_t kHeight = 128;
1666     constexpr uint32_t kLayers = 6u;
1667     constexpr uint32_t kBaseLayer = 2u;
1668     constexpr uint32_t kCopyLayers = 3u;
1669 
1670     constexpr uint32_t kRowsPerImage = kHeight * 2;
1671 
1672     TextureSpec textureSpec;
1673     textureSpec.copyOrigin = {0, 0, kBaseLayer};
1674     textureSpec.textureSize = {kWidth, kHeight, kLayers};
1675 
1676     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
1677     bufferSpec.rowsPerImage = kRowsPerImage;
1678     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers});
1679 }
1680 
1681 // Test a special code path in the D3D12 backends when (BytesPerRow * RowsPerImage) is not a
1682 // multiple of 512.
TEST_P(CopyTests_B2T,Texture2DArrayRegionWithOffsetOddRowsPerImage)1683 TEST_P(CopyTests_B2T, Texture2DArrayRegionWithOffsetOddRowsPerImage) {
1684     constexpr uint32_t kWidth = 64;
1685     constexpr uint32_t kHeight = 128;
1686     constexpr uint32_t kLayers = 8u;
1687     constexpr uint32_t kBaseLayer = 2u;
1688     constexpr uint32_t kCopyLayers = 5u;
1689 
1690     constexpr uint32_t kRowsPerImage = kHeight + 1;
1691 
1692     TextureSpec textureSpec;
1693     textureSpec.copyOrigin = {0, 0, kBaseLayer};
1694     textureSpec.textureSize = {kWidth, kHeight, kLayers};
1695 
1696     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
1697     bufferSpec.offset += 128u;
1698     bufferSpec.size += 128u;
1699     bufferSpec.rowsPerImage = kRowsPerImage;
1700     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers});
1701 }
1702 
1703 // Test a special code path in the D3D12 backends when (BytesPerRow * RowsPerImage) is a multiple
1704 // of 512.
TEST_P(CopyTests_B2T,Texture2DArrayRegionWithOffsetEvenRowsPerImage)1705 TEST_P(CopyTests_B2T, Texture2DArrayRegionWithOffsetEvenRowsPerImage) {
1706     constexpr uint32_t kWidth = 64;
1707     constexpr uint32_t kHeight = 128;
1708     constexpr uint32_t kLayers = 8u;
1709     constexpr uint32_t kBaseLayer = 2u;
1710     constexpr uint32_t kCopyLayers = 5u;
1711 
1712     constexpr uint32_t kRowsPerImage = kHeight + 2;
1713 
1714     TextureSpec textureSpec;
1715     textureSpec.copyOrigin = {0, 0, kBaseLayer};
1716     textureSpec.textureSize = {kWidth, kHeight, kLayers};
1717 
1718     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
1719     bufferSpec.offset += 128u;
1720     bufferSpec.size += 128u;
1721     bufferSpec.rowsPerImage = kRowsPerImage;
1722     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers});
1723 }
1724 
1725 // Test that copying whole texture 3D in one buffer-to-texture-copy works.
TEST_P(CopyTests_B2T,Texture3DFull)1726 TEST_P(CopyTests_B2T, Texture3DFull) {
1727     constexpr uint32_t kWidth = 256;
1728     constexpr uint32_t kHeight = 128;
1729     constexpr uint32_t kDepth = 6;
1730 
1731     TextureSpec textureSpec;
1732     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1733 
1734     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kDepth), {kWidth, kHeight, kDepth},
1735            wgpu::TextureDimension::e3D);
1736 }
1737 
1738 // Test that copying a range of texture 3D Depths in one texture-to-buffer-copy works.
TEST_P(CopyTests_B2T,Texture3DSubRegion)1739 TEST_P(CopyTests_B2T, Texture3DSubRegion) {
1740     DAWN_TEST_UNSUPPORTED_IF(IsANGLE());  // TODO(crbug.com/angleproject/5967)
1741 
1742     constexpr uint32_t kWidth = 256;
1743     constexpr uint32_t kHeight = 128;
1744     constexpr uint32_t kDepth = 6;
1745     constexpr uint32_t kBaseDepth = 2u;
1746     constexpr uint32_t kCopyDepth = 3u;
1747 
1748     TextureSpec textureSpec;
1749     textureSpec.copyOrigin = {0, 0, kBaseDepth};
1750     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1751 
1752     DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kCopyDepth),
1753            {kWidth / 2, kHeight / 2, kCopyDepth}, wgpu::TextureDimension::e3D);
1754 }
1755 
TEST_P(CopyTests_B2T,Texture3DNoSplitRowDataWithEmptyFirstRow)1756 TEST_P(CopyTests_B2T, Texture3DNoSplitRowDataWithEmptyFirstRow) {
1757     constexpr uint32_t kWidth = 2;
1758     constexpr uint32_t kHeight = 4;
1759     constexpr uint32_t kDepth = 3;
1760 
1761     TextureSpec textureSpec;
1762     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1763     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight, kDepth);
1764 
1765     // The tests below are designed to test TextureCopySplitter for 3D textures on D3D12.
1766     // Base: no split for a row + no empty first row
1767     bufferSpec.offset = 60;
1768     bufferSpec.size += bufferSpec.offset;
1769     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1770 
1771     // This test will cover: no split for a row + empty first row
1772     bufferSpec.offset = 260;
1773     bufferSpec.size += bufferSpec.offset;
1774     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1775 }
1776 
TEST_P(CopyTests_B2T,Texture3DSplitRowDataWithoutEmptyFirstRow)1777 TEST_P(CopyTests_B2T, Texture3DSplitRowDataWithoutEmptyFirstRow) {
1778     constexpr uint32_t kWidth = 259;
1779     constexpr uint32_t kHeight = 127;
1780     constexpr uint32_t kDepth = 3;
1781 
1782     TextureSpec textureSpec;
1783     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1784     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight, kDepth);
1785 
1786     // The test below is designed to test TextureCopySplitter for 3D textures on D3D12.
1787     // This test will cover: split for a row + no empty first row for both split regions
1788     bufferSpec.offset = 260;
1789     bufferSpec.size += bufferSpec.offset;
1790     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1791 }
1792 
TEST_P(CopyTests_B2T,Texture3DSplitRowDataWithEmptyFirstRow)1793 TEST_P(CopyTests_B2T, Texture3DSplitRowDataWithEmptyFirstRow) {
1794     constexpr uint32_t kWidth = 39;
1795     constexpr uint32_t kHeight = 4;
1796     constexpr uint32_t kDepth = 3;
1797 
1798     TextureSpec textureSpec;
1799     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1800     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight, kDepth);
1801 
1802     // The tests below are designed to test TextureCopySplitter for 3D textures on D3D12.
1803     // This test will cover: split for a row + empty first row for the head block
1804     bufferSpec.offset = 400;
1805     bufferSpec.size += bufferSpec.offset;
1806     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1807 
1808     // This test will cover: split for a row + empty first row for the tail block
1809     bufferSpec.offset = 160;
1810     bufferSpec.size += bufferSpec.offset;
1811     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1812 }
1813 
TEST_P(CopyTests_B2T,Texture3DCopyHeightIsOneCopyWidthIsTiny)1814 TEST_P(CopyTests_B2T, Texture3DCopyHeightIsOneCopyWidthIsTiny) {
1815     constexpr uint32_t kWidth = 2;
1816     constexpr uint32_t kHeight = 1;
1817     constexpr uint32_t kDepth = 3;
1818 
1819     TextureSpec textureSpec;
1820     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1821     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight, kDepth);
1822 
1823     // The tests below are designed to test TextureCopySplitter for 3D textures on D3D12.
1824     // Base: no split for a row, no empty row, and copy height is 1
1825     bufferSpec.offset = 60;
1826     bufferSpec.size += bufferSpec.offset;
1827     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1828 
1829     // This test will cover: no split for a row + empty first row, and copy height is 1
1830     bufferSpec.offset = 260;
1831     bufferSpec.size += bufferSpec.offset;
1832     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1833 }
1834 
TEST_P(CopyTests_B2T,Texture3DCopyHeightIsOneCopyWidthIsSmall)1835 TEST_P(CopyTests_B2T, Texture3DCopyHeightIsOneCopyWidthIsSmall) {
1836     constexpr uint32_t kWidth = 39;
1837     constexpr uint32_t kHeight = 1;
1838     constexpr uint32_t kDepth = 3;
1839 
1840     TextureSpec textureSpec;
1841     textureSpec.textureSize = {kWidth, kHeight, kDepth};
1842     BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight, kDepth);
1843 
1844     // The tests below are designed to test TextureCopySplitter for 3D textures on D3D12.
1845     // This test will cover: split for a row + empty first row for the head block, and copy height
1846     // is 1
1847     bufferSpec.offset = 400;
1848     bufferSpec.size += bufferSpec.offset;
1849     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1850 
1851     // This test will cover: split for a row + empty first row for the tail block, and copy height
1852     // is 1
1853     bufferSpec.offset = 160;
1854     bufferSpec.size += bufferSpec.offset;
1855     DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
1856 }
1857 
1858 // Test that copying texture 3D array mips with 256-byte aligned sizes works
TEST_P(CopyTests_B2T,Texture3DMipAligned)1859 TEST_P(CopyTests_B2T, Texture3DMipAligned) {
1860     constexpr uint32_t kWidth = 256;
1861     constexpr uint32_t kHeight = 128;
1862     constexpr uint32_t kDepth = 64u;
1863 
1864     TextureSpec defaultTextureSpec;
1865     defaultTextureSpec.textureSize = {kWidth, kHeight, kDepth};
1866 
1867     for (unsigned int i = 1; i < 6; ++i) {
1868         TextureSpec textureSpec = defaultTextureSpec;
1869         textureSpec.copyLevel = i;
1870         textureSpec.levelCount = i + 1;
1871 
1872         DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i, kDepth >> i),
1873                {kWidth >> i, kHeight >> i, kDepth >> i}, wgpu::TextureDimension::e3D);
1874     }
1875 }
1876 
1877 // Test that copying texture 3D array mips with 256-byte unaligned sizes works
TEST_P(CopyTests_B2T,Texture3DMipUnaligned)1878 TEST_P(CopyTests_B2T, Texture3DMipUnaligned) {
1879     constexpr uint32_t kWidth = 261;
1880     constexpr uint32_t kHeight = 123;
1881     constexpr uint32_t kDepth = 69u;
1882 
1883     TextureSpec defaultTextureSpec;
1884     defaultTextureSpec.textureSize = {kWidth, kHeight, kDepth};
1885 
1886     for (unsigned int i = 1; i < 6; ++i) {
1887         TextureSpec textureSpec = defaultTextureSpec;
1888         textureSpec.copyLevel = i;
1889         textureSpec.levelCount = i + 1;
1890 
1891         DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i, kDepth >> i),
1892                {kWidth >> i, kHeight >> i, kDepth >> i}, wgpu::TextureDimension::e3D);
1893     }
1894 }
1895 
1896 DAWN_INSTANTIATE_TEST(CopyTests_B2T,
1897                       D3D12Backend(),
1898                       MetalBackend(),
1899                       OpenGLBackend(),
1900                       OpenGLESBackend(),
1901                       VulkanBackend());
1902 
TEST_P(CopyTests_T2T,Texture)1903 TEST_P(CopyTests_T2T, Texture) {
1904     constexpr uint32_t kWidth = 256;
1905     constexpr uint32_t kHeight = 128;
1906 
1907     TextureSpec textureSpec;
1908     textureSpec.textureSize = {kWidth, kHeight, 1};
1909     DoTest(textureSpec, textureSpec, {kWidth, kHeight, 1});
1910 }
1911 
1912 // Test noop copies.
TEST_P(CopyTests_T2T,ZeroSizedCopy)1913 TEST_P(CopyTests_T2T, ZeroSizedCopy) {
1914     constexpr uint32_t kWidth = 256;
1915     constexpr uint32_t kHeight = 128;
1916 
1917     TextureSpec textureSpec;
1918     textureSpec.textureSize = {kWidth, kHeight, 1};
1919     DoTest(textureSpec, textureSpec, {0, kHeight, 1});
1920     DoTest(textureSpec, textureSpec, {kWidth, 0, 1});
1921     DoTest(textureSpec, textureSpec, {kWidth, kHeight, 0});
1922 }
1923 
TEST_P(CopyTests_T2T,TextureRegion)1924 TEST_P(CopyTests_T2T, TextureRegion) {
1925     constexpr uint32_t kWidth = 256;
1926     constexpr uint32_t kHeight = 128;
1927 
1928     TextureSpec defaultTextureSpec;
1929     defaultTextureSpec.textureSize = {kWidth, kHeight, 1};
1930 
1931     for (unsigned int w : {64, 128, 256}) {
1932         for (unsigned int h : {16, 32, 48}) {
1933             TextureSpec textureSpec = defaultTextureSpec;
1934             DoTest(textureSpec, textureSpec, {w, h, 1});
1935         }
1936     }
1937 }
1938 
TEST_P(CopyTests_T2T,TextureMip)1939 TEST_P(CopyTests_T2T, TextureMip) {
1940     constexpr uint32_t kWidth = 256;
1941     constexpr uint32_t kHeight = 128;
1942 
1943     TextureSpec defaultTextureSpec;
1944     defaultTextureSpec.textureSize = {kWidth, kHeight, 1};
1945 
1946     for (unsigned int i = 1; i < 4; ++i) {
1947         TextureSpec textureSpec = defaultTextureSpec;
1948         textureSpec.copyLevel = i;
1949         textureSpec.levelCount = i + 1;
1950 
1951         DoTest(textureSpec, textureSpec, {kWidth >> i, kHeight >> i, 1});
1952     }
1953 }
1954 
TEST_P(CopyTests_T2T,SingleMipSrcMultipleMipDst)1955 TEST_P(CopyTests_T2T, SingleMipSrcMultipleMipDst) {
1956     constexpr uint32_t kWidth = 256;
1957     constexpr uint32_t kHeight = 128;
1958 
1959     TextureSpec defaultTextureSpec;
1960 
1961     for (unsigned int i = 1; i < 4; ++i) {
1962         TextureSpec srcTextureSpec = defaultTextureSpec;
1963         srcTextureSpec.textureSize = {kWidth >> i, kHeight >> i, 1};
1964 
1965         TextureSpec dstTextureSpec = defaultTextureSpec;
1966         dstTextureSpec.textureSize = {kWidth, kHeight, 1};
1967         dstTextureSpec.copyLevel = i;
1968         dstTextureSpec.levelCount = i + 1;
1969 
1970         DoTest(srcTextureSpec, dstTextureSpec, {kWidth >> i, kHeight >> i, 1});
1971     }
1972 }
1973 
TEST_P(CopyTests_T2T,MultipleMipSrcSingleMipDst)1974 TEST_P(CopyTests_T2T, MultipleMipSrcSingleMipDst) {
1975     constexpr uint32_t kWidth = 256;
1976     constexpr uint32_t kHeight = 128;
1977 
1978     TextureSpec defaultTextureSpec;
1979 
1980     for (unsigned int i = 1; i < 4; ++i) {
1981         TextureSpec srcTextureSpec = defaultTextureSpec;
1982         srcTextureSpec.textureSize = {kWidth, kHeight, 1};
1983         srcTextureSpec.copyLevel = i;
1984         srcTextureSpec.levelCount = i + 1;
1985 
1986         TextureSpec dstTextureSpec = defaultTextureSpec;
1987         dstTextureSpec.textureSize = {kWidth >> i, kHeight >> i, 1};
1988 
1989         DoTest(srcTextureSpec, dstTextureSpec, {kWidth >> i, kHeight >> i, 1});
1990     }
1991 }
1992 
1993 // Test that copying from one mip level to another mip level within the same 2D texture works.
TEST_P(CopyTests_T2T,Texture2DSameTextureDifferentMipLevels)1994 TEST_P(CopyTests_T2T, Texture2DSameTextureDifferentMipLevels) {
1995     constexpr uint32_t kWidth = 256;
1996     constexpr uint32_t kHeight = 128;
1997 
1998     TextureSpec defaultTextureSpec;
1999     defaultTextureSpec.textureSize = {kWidth, kHeight, 1};
2000     defaultTextureSpec.levelCount = 6;
2001 
2002     for (unsigned int i = 1; i < 6; ++i) {
2003         TextureSpec srcSpec = defaultTextureSpec;
2004         srcSpec.copyLevel = i - 1;
2005         TextureSpec dstSpec = defaultTextureSpec;
2006         dstSpec.copyLevel = i;
2007 
2008         DoTest(srcSpec, dstSpec, {kWidth >> i, kHeight >> i, 1}, true);
2009     }
2010 }
2011 
2012 // Test copying the whole 2D array texture.
TEST_P(CopyTests_T2T,Texture2DArrayFull)2013 TEST_P(CopyTests_T2T, Texture2DArrayFull) {
2014     constexpr uint32_t kWidth = 256;
2015     constexpr uint32_t kHeight = 128;
2016     constexpr uint32_t kLayers = 6u;
2017 
2018     TextureSpec textureSpec;
2019     textureSpec.textureSize = {kWidth, kHeight, kLayers};
2020 
2021     DoTest(textureSpec, textureSpec, {kWidth, kHeight, kLayers});
2022 }
2023 
2024 // Test copying a subresource region of the 2D array texture.
TEST_P(CopyTests_T2T,Texture2DArrayRegion)2025 TEST_P(CopyTests_T2T, Texture2DArrayRegion) {
2026     constexpr uint32_t kWidth = 256;
2027     constexpr uint32_t kHeight = 128;
2028     constexpr uint32_t kLayers = 6u;
2029 
2030     TextureSpec defaultTextureSpec;
2031     defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers};
2032 
2033     for (unsigned int w : {64, 128, 256}) {
2034         for (unsigned int h : {16, 32, 48}) {
2035             TextureSpec textureSpec = defaultTextureSpec;
2036             DoTest(textureSpec, textureSpec, {w, h, kLayers});
2037         }
2038     }
2039 }
2040 
2041 // Test copying one slice of a 2D array texture.
TEST_P(CopyTests_T2T,Texture2DArrayCopyOneSlice)2042 TEST_P(CopyTests_T2T, Texture2DArrayCopyOneSlice) {
2043     constexpr uint32_t kWidth = 256;
2044     constexpr uint32_t kHeight = 128;
2045     constexpr uint32_t kLayers = 6u;
2046     constexpr uint32_t kSrcBaseLayer = 1u;
2047     constexpr uint32_t kDstBaseLayer = 3u;
2048     constexpr uint32_t kCopyArrayLayerCount = 1u;
2049 
2050     TextureSpec defaultTextureSpec;
2051     defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers};
2052 
2053     TextureSpec srcTextureSpec = defaultTextureSpec;
2054     srcTextureSpec.copyOrigin = {0, 0, kSrcBaseLayer};
2055 
2056     TextureSpec dstTextureSpec = defaultTextureSpec;
2057     dstTextureSpec.copyOrigin = {0, 0, kDstBaseLayer};
2058 
2059     DoTest(srcTextureSpec, dstTextureSpec, {kWidth, kHeight, kCopyArrayLayerCount});
2060 }
2061 
2062 // Test copying multiple contiguous slices of a 2D array texture.
TEST_P(CopyTests_T2T,Texture2DArrayCopyMultipleSlices)2063 TEST_P(CopyTests_T2T, Texture2DArrayCopyMultipleSlices) {
2064     constexpr uint32_t kWidth = 256;
2065     constexpr uint32_t kHeight = 128;
2066     constexpr uint32_t kLayers = 6u;
2067     constexpr uint32_t kSrcBaseLayer = 0u;
2068     constexpr uint32_t kDstBaseLayer = 3u;
2069     constexpr uint32_t kCopyArrayLayerCount = 3u;
2070 
2071     TextureSpec defaultTextureSpec;
2072     defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers};
2073 
2074     TextureSpec srcTextureSpec = defaultTextureSpec;
2075     srcTextureSpec.copyOrigin = {0, 0, kSrcBaseLayer};
2076 
2077     TextureSpec dstTextureSpec = defaultTextureSpec;
2078     dstTextureSpec.copyOrigin = {0, 0, kDstBaseLayer};
2079 
2080     DoTest(srcTextureSpec, dstTextureSpec, {kWidth, kHeight, kCopyArrayLayerCount});
2081 }
2082 
2083 // Test copying one texture slice within the same texture.
TEST_P(CopyTests_T2T,CopyWithinSameTextureOneSlice)2084 TEST_P(CopyTests_T2T, CopyWithinSameTextureOneSlice) {
2085     constexpr uint32_t kWidth = 256u;
2086     constexpr uint32_t kHeight = 128u;
2087     constexpr uint32_t kLayers = 6u;
2088     constexpr uint32_t kSrcBaseLayer = 0u;
2089     constexpr uint32_t kDstBaseLayer = 3u;
2090     constexpr uint32_t kCopyArrayLayerCount = 1u;
2091 
2092     TextureSpec defaultTextureSpec;
2093     defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers};
2094 
2095     TextureSpec srcTextureSpec = defaultTextureSpec;
2096     srcTextureSpec.copyOrigin = {0, 0, kSrcBaseLayer};
2097 
2098     TextureSpec dstTextureSpec = defaultTextureSpec;
2099     dstTextureSpec.copyOrigin = {0, 0, kDstBaseLayer};
2100 
2101     DoTest(srcTextureSpec, dstTextureSpec, {kWidth, kHeight, kCopyArrayLayerCount}, true);
2102 }
2103 
2104 // Test copying multiple contiguous texture slices within the same texture with non-overlapped
2105 // slices.
TEST_P(CopyTests_T2T,CopyWithinSameTextureNonOverlappedSlices)2106 TEST_P(CopyTests_T2T, CopyWithinSameTextureNonOverlappedSlices) {
2107     constexpr uint32_t kWidth = 256u;
2108     constexpr uint32_t kHeight = 128u;
2109     constexpr uint32_t kLayers = 6u;
2110     constexpr uint32_t kSrcBaseLayer = 0u;
2111     constexpr uint32_t kDstBaseLayer = 3u;
2112     constexpr uint32_t kCopyArrayLayerCount = 3u;
2113 
2114     TextureSpec defaultTextureSpec;
2115     defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers};
2116 
2117     TextureSpec srcTextureSpec = defaultTextureSpec;
2118     srcTextureSpec.copyOrigin = {0, 0, kSrcBaseLayer};
2119 
2120     TextureSpec dstTextureSpec = defaultTextureSpec;
2121     dstTextureSpec.copyOrigin = {0, 0, kDstBaseLayer};
2122 
2123     DoTest(srcTextureSpec, dstTextureSpec, {kWidth, kHeight, kCopyArrayLayerCount}, true);
2124 }
2125 
2126 // A regression test (from WebGPU CTS) for an Intel D3D12 driver bug about T2T copy with specific
2127 // texture formats. See http://crbug.com/1161355 for more details.
TEST_P(CopyTests_T2T,CopyFromNonZeroMipLevelWithTexelBlockSizeLessThan4Bytes)2128 TEST_P(CopyTests_T2T, CopyFromNonZeroMipLevelWithTexelBlockSizeLessThan4Bytes) {
2129     // This test can pass on the Windows Intel Vulkan driver version 27.20.100.9168.
2130     // TODO(crbug.com/dawn/819): enable this test on Intel Vulkan drivers after the upgrade of
2131     // try bots.
2132     DAWN_SUPPRESS_TEST_IF(IsVulkan() && IsWindows() && IsIntel());
2133 
2134     constexpr std::array<wgpu::TextureFormat, 11> kFormats = {
2135         {wgpu::TextureFormat::RG8Sint, wgpu::TextureFormat::RG8Uint, wgpu::TextureFormat::RG8Snorm,
2136          wgpu::TextureFormat::RG8Unorm, wgpu::TextureFormat::R16Float, wgpu::TextureFormat::R16Sint,
2137          wgpu::TextureFormat::R16Uint, wgpu::TextureFormat::R8Snorm, wgpu::TextureFormat::R8Unorm,
2138          wgpu::TextureFormat::R8Sint, wgpu::TextureFormat::R8Uint}};
2139 
2140     constexpr uint32_t kSrcLevelCount = 4;
2141     constexpr uint32_t kDstLevelCount = 5;
2142     constexpr uint32_t kSrcSize = 2 << kSrcLevelCount;
2143     constexpr uint32_t kDstSize = 2 << kDstLevelCount;
2144     ASSERT_LE(kSrcSize, kTextureBytesPerRowAlignment);
2145     ASSERT_LE(kDstSize, kTextureBytesPerRowAlignment);
2146 
2147     // The copyLayer to test:
2148     // 1u (non-array texture), 3u (copyLayer < copyWidth), 5u (copyLayer > copyWidth)
2149     constexpr std::array<uint32_t, 3> kTestTextureLayer = {1u, 3u, 5u};
2150 
2151     for (wgpu::TextureFormat format : kFormats) {
2152         if (HasToggleEnabled("disable_snorm_read") &&
2153             (format == wgpu::TextureFormat::RG8Snorm || format == wgpu::TextureFormat::R8Snorm)) {
2154             continue;
2155         }
2156 
2157         if (HasToggleEnabled("disable_r8_rg8_mipmaps") &&
2158             (format == wgpu::TextureFormat::R8Unorm || format == wgpu::TextureFormat::RG8Unorm)) {
2159             continue;
2160         }
2161 
2162         for (uint32_t textureLayer : kTestTextureLayer) {
2163             const wgpu::Extent3D kUploadSize = {4u, 4u, textureLayer};
2164 
2165             for (uint32_t srcLevel = 0; srcLevel < kSrcLevelCount; ++srcLevel) {
2166                 for (uint32_t dstLevel = 0; dstLevel < kDstLevelCount; ++dstLevel) {
2167                     TextureSpec srcSpec;
2168                     srcSpec.levelCount = kSrcLevelCount;
2169                     srcSpec.format = format;
2170                     srcSpec.copyLevel = srcLevel;
2171                     srcSpec.textureSize = {kSrcSize, kSrcSize, textureLayer};
2172 
2173                     TextureSpec dstSpec = srcSpec;
2174                     dstSpec.levelCount = kDstLevelCount;
2175                     dstSpec.copyLevel = dstLevel;
2176                     dstSpec.textureSize = {kDstSize, kDstSize, textureLayer};
2177 
2178                     DoTest(srcSpec, dstSpec, kUploadSize);
2179                 }
2180             }
2181         }
2182     }
2183 }
2184 
2185 // Test that copying from one mip level to another mip level within the same 2D array texture works.
TEST_P(CopyTests_T2T,Texture2DArraySameTextureDifferentMipLevels)2186 TEST_P(CopyTests_T2T, Texture2DArraySameTextureDifferentMipLevels) {
2187     constexpr uint32_t kWidth = 256;
2188     constexpr uint32_t kHeight = 128;
2189     constexpr uint32_t kLayers = 8u;
2190 
2191     TextureSpec defaultTextureSpec;
2192     defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers};
2193     defaultTextureSpec.levelCount = 6;
2194 
2195     for (unsigned int i = 1; i < 6; ++i) {
2196         TextureSpec srcSpec = defaultTextureSpec;
2197         srcSpec.copyLevel = i - 1;
2198         TextureSpec dstSpec = defaultTextureSpec;
2199         dstSpec.copyLevel = i;
2200 
2201         DoTest(srcSpec, dstSpec, {kWidth >> i, kHeight >> i, kLayers}, true);
2202     }
2203 }
2204 
2205 // Test that copying whole 3D texture in one texture-to-texture-copy works.
TEST_P(CopyTests_T2T,Texture3DFull)2206 TEST_P(CopyTests_T2T, Texture3DFull) {
2207     constexpr uint32_t kWidth = 256;
2208     constexpr uint32_t kHeight = 128;
2209     constexpr uint32_t kDepth = 6u;
2210 
2211     TextureSpec textureSpec;
2212     textureSpec.textureSize = {kWidth, kHeight, kDepth};
2213 
2214     DoTest(textureSpec, textureSpec, {kWidth, kHeight, kDepth}, false, wgpu::TextureDimension::e3D);
2215 }
2216 
2217 // Test that copying from one mip level to another mip level within the same 3D texture works.
TEST_P(CopyTests_T2T,Texture3DSameTextureDifferentMipLevels)2218 TEST_P(CopyTests_T2T, Texture3DSameTextureDifferentMipLevels) {
2219     constexpr uint32_t kWidth = 256;
2220     constexpr uint32_t kHeight = 128;
2221     constexpr uint32_t kDepth = 6u;
2222 
2223     TextureSpec textureSpec;
2224     textureSpec.textureSize = {kWidth, kHeight, kDepth};
2225     textureSpec.levelCount = 2;
2226 
2227     TextureSpec dstSpec = textureSpec;
2228     dstSpec.copyLevel = 1;
2229 
2230     DoTest(textureSpec, dstSpec, {kWidth >> 1, kHeight >> 1, kDepth >> 1}, true,
2231            wgpu::TextureDimension::e3D);
2232 }
2233 
2234 // Test that copying whole 3D texture to a 2D array in one texture-to-texture-copy works.
TEST_P(CopyTests_T2T,Texture3DTo2DArrayFull)2235 TEST_P(CopyTests_T2T, Texture3DTo2DArrayFull) {
2236     constexpr uint32_t kWidth = 256;
2237     constexpr uint32_t kHeight = 128;
2238     constexpr uint32_t kDepth = 6u;
2239 
2240     TextureSpec textureSpec;
2241     textureSpec.textureSize = {kWidth, kHeight, kDepth};
2242 
2243     DoTest(textureSpec, textureSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D,
2244            wgpu::TextureDimension::e2D);
2245 }
2246 
2247 // Test that copying between 3D texture and 2D array textures works. It includes partial copy
2248 // for src and/or dst texture, non-zero offset (copy origin), non-zero mip level.
TEST_P(CopyTests_T2T,Texture3DAnd2DArraySubRegion)2249 TEST_P(CopyTests_T2T, Texture3DAnd2DArraySubRegion) {
2250     DAWN_TEST_UNSUPPORTED_IF(IsANGLE());  // TODO(crbug.com/angleproject/5967)
2251     // TODO(crbug.com/dawn/1216): Remove this suppression.
2252     DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsNvidia());
2253 
2254     constexpr uint32_t kWidth = 8;
2255     constexpr uint32_t kHeight = 4;
2256     constexpr uint32_t kDepth = 2u;
2257 
2258     TextureSpec baseSpec;
2259     baseSpec.textureSize = {kWidth, kHeight, kDepth};
2260 
2261     TextureSpec srcSpec = baseSpec;
2262     TextureSpec dstSpec = baseSpec;
2263 
2264     // dst texture is a partial copy
2265     dstSpec.textureSize = {kWidth * 2, kHeight * 2, kDepth * 2};
2266     DoTest(srcSpec, dstSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D,
2267            wgpu::TextureDimension::e2D);
2268     DoTest(srcSpec, dstSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e2D,
2269            wgpu::TextureDimension::e3D);
2270 
2271     // src texture is a partial copy
2272     srcSpec.textureSize = {kWidth * 2, kHeight * 2, kDepth * 2};
2273     dstSpec = baseSpec;
2274     DoTest(srcSpec, dstSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D,
2275            wgpu::TextureDimension::e2D);
2276     DoTest(srcSpec, dstSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e2D,
2277            wgpu::TextureDimension::e3D);
2278 
2279     // Both src and dst texture is a partial copy
2280     srcSpec.textureSize = {kWidth * 2, kHeight * 2, kDepth * 2};
2281     dstSpec.textureSize = {kWidth * 2, kHeight * 2, kDepth * 2};
2282     DoTest(srcSpec, dstSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D,
2283            wgpu::TextureDimension::e2D);
2284     DoTest(srcSpec, dstSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e2D,
2285            wgpu::TextureDimension::e3D);
2286 
2287     // Non-zero offset (copy origin)
2288     srcSpec = baseSpec;
2289     dstSpec.textureSize = {kWidth * 2, kHeight * 2, kDepth * 2};
2290     dstSpec.copyOrigin = {kWidth, kHeight, kDepth};
2291     DoTest(srcSpec, dstSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D,
2292            wgpu::TextureDimension::e2D);
2293     DoTest(srcSpec, dstSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e2D,
2294            wgpu::TextureDimension::e3D);
2295 
2296     // Non-zero mip level
2297     srcSpec = baseSpec;
2298     dstSpec.textureSize = {kWidth * 2, kHeight * 2, kDepth * 2};
2299     dstSpec.copyOrigin = {0, 0, 0};
2300     dstSpec.copyLevel = 1;
2301     dstSpec.levelCount = 2;
2302     DoTest(srcSpec, dstSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D,
2303            wgpu::TextureDimension::e2D);
2304     DoTest(srcSpec, dstSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e2D,
2305            wgpu::TextureDimension::e3D);
2306 }
2307 
2308 // Test that copying whole 2D array to a 3D texture in one texture-to-texture-copy works.
TEST_P(CopyTests_T2T,Texture2DArrayTo3DFull)2309 TEST_P(CopyTests_T2T, Texture2DArrayTo3DFull) {
2310     // TODO(crbug.com/dawn/1216): Remove this suppression.
2311     DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsNvidia());
2312     constexpr uint32_t kWidth = 256;
2313     constexpr uint32_t kHeight = 128;
2314     constexpr uint32_t kDepth = 6u;
2315 
2316     TextureSpec textureSpec;
2317     textureSpec.textureSize = {kWidth, kHeight, kDepth};
2318 
2319     DoTest(textureSpec, textureSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e2D,
2320            wgpu::TextureDimension::e3D);
2321 }
2322 
2323 // Test that copying subregion of a 3D texture in one texture-to-texture-copy works.
TEST_P(CopyTests_T2T,Texture3DSubRegion)2324 TEST_P(CopyTests_T2T, Texture3DSubRegion) {
2325     DAWN_TEST_UNSUPPORTED_IF(IsANGLE());  // TODO(crbug.com/angleproject/5967)
2326     constexpr uint32_t kWidth = 256;
2327     constexpr uint32_t kHeight = 128;
2328     constexpr uint32_t kDepth = 6u;
2329 
2330     TextureSpec textureSpec;
2331     textureSpec.textureSize = {kWidth, kHeight, kDepth};
2332 
2333     DoTest(textureSpec, textureSpec, {kWidth / 2, kHeight / 2, kDepth / 2}, false,
2334            wgpu::TextureDimension::e3D);
2335 }
2336 
2337 // Test that copying subregion of a 3D texture to a 2D array in one texture-to-texture-copy works.
TEST_P(CopyTests_T2T,Texture3DTo2DArraySubRegion)2338 TEST_P(CopyTests_T2T, Texture3DTo2DArraySubRegion) {
2339     constexpr uint32_t kWidth = 256;
2340     constexpr uint32_t kHeight = 128;
2341     constexpr uint32_t kDepth = 6u;
2342 
2343     TextureSpec textureSpec;
2344     textureSpec.textureSize = {kWidth, kHeight, kDepth};
2345 
2346     DoTest(textureSpec, textureSpec, {kWidth / 2, kHeight / 2, kDepth / 2},
2347            wgpu::TextureDimension::e3D, wgpu::TextureDimension::e2D);
2348 }
2349 
2350 // Test that copying subregion of a 2D array to a 3D texture to in one texture-to-texture-copy
2351 // works.
TEST_P(CopyTests_T2T,Texture2DArrayTo3DSubRegion)2352 TEST_P(CopyTests_T2T, Texture2DArrayTo3DSubRegion) {
2353     DAWN_TEST_UNSUPPORTED_IF(IsANGLE());  // TODO(crbug.com/angleproject/5967)
2354     // TODO(crbug.com/dawn/1216): Remove this suppression.
2355     DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsNvidia());
2356     constexpr uint32_t kWidth = 256;
2357     constexpr uint32_t kHeight = 128;
2358     constexpr uint32_t kDepth = 6u;
2359 
2360     TextureSpec textureSpec;
2361     textureSpec.textureSize = {kWidth, kHeight, kDepth};
2362 
2363     DoTest(textureSpec, textureSpec, {kWidth / 2, kHeight / 2, kDepth / 2},
2364            wgpu::TextureDimension::e2D, wgpu::TextureDimension::e3D);
2365 }
2366 
2367 // Test that copying texture 3D array mips in one texture-to-texture-copy works
TEST_P(CopyTests_T2T,Texture3DMipAligned)2368 TEST_P(CopyTests_T2T, Texture3DMipAligned) {
2369     constexpr uint32_t kWidth = 256;
2370     constexpr uint32_t kHeight = 128;
2371     constexpr uint32_t kDepth = 64u;
2372 
2373     TextureSpec defaultTextureSpec;
2374     defaultTextureSpec.textureSize = {kWidth, kHeight, kDepth};
2375 
2376     for (unsigned int i = 1; i < 6; ++i) {
2377         TextureSpec textureSpec = defaultTextureSpec;
2378         textureSpec.copyLevel = i;
2379         textureSpec.levelCount = i + 1;
2380 
2381         DoTest(textureSpec, textureSpec, {kWidth >> i, kHeight >> i, kDepth >> i},
2382                wgpu::TextureDimension::e3D, wgpu::TextureDimension::e3D);
2383     }
2384 }
2385 
2386 // Test that copying texture 3D array mips in one texture-to-texture-copy works
TEST_P(CopyTests_T2T,Texture3DMipUnaligned)2387 TEST_P(CopyTests_T2T, Texture3DMipUnaligned) {
2388     constexpr uint32_t kWidth = 261;
2389     constexpr uint32_t kHeight = 123;
2390     constexpr uint32_t kDepth = 69u;
2391 
2392     TextureSpec defaultTextureSpec;
2393     defaultTextureSpec.textureSize = {kWidth, kHeight, kDepth};
2394 
2395     for (unsigned int i = 1; i < 6; ++i) {
2396         TextureSpec textureSpec = defaultTextureSpec;
2397         textureSpec.copyLevel = i;
2398         textureSpec.levelCount = i + 1;
2399 
2400         DoTest(textureSpec, textureSpec, {kWidth >> i, kHeight >> i, kDepth >> i},
2401                wgpu::TextureDimension::e3D, wgpu::TextureDimension::e3D);
2402     }
2403 }
2404 
2405 DAWN_INSTANTIATE_TEST_P(CopyTests_T2T,
2406                         {D3D12Backend(),
2407                          D3D12Backend({"use_temp_buffer_in_small_format_texture_to_texture_copy_"
2408                                        "from_greater_to_less_mip_level"}),
2409                          MetalBackend(), OpenGLBackend(), OpenGLESBackend(), VulkanBackend()},
2410                         {true, false});
2411 
2412 static constexpr uint64_t kSmallBufferSize = 4;
2413 static constexpr uint64_t kLargeBufferSize = 1 << 16;
2414 
2415 // Test copying full buffers
TEST_P(CopyTests_B2B,FullCopy)2416 TEST_P(CopyTests_B2B, FullCopy) {
2417     DoTest(kSmallBufferSize, 0, kSmallBufferSize, 0, kSmallBufferSize);
2418     DoTest(kLargeBufferSize, 0, kLargeBufferSize, 0, kLargeBufferSize);
2419 }
2420 
2421 // Test copying small pieces of a buffer at different corner case offsets
TEST_P(CopyTests_B2B,SmallCopyInBigBuffer)2422 TEST_P(CopyTests_B2B, SmallCopyInBigBuffer) {
2423     constexpr uint64_t kEndOffset = kLargeBufferSize - kSmallBufferSize;
2424     DoTest(kLargeBufferSize, 0, kLargeBufferSize, 0, kSmallBufferSize);
2425     DoTest(kLargeBufferSize, kEndOffset, kLargeBufferSize, 0, kSmallBufferSize);
2426     DoTest(kLargeBufferSize, 0, kLargeBufferSize, kEndOffset, kSmallBufferSize);
2427     DoTest(kLargeBufferSize, kEndOffset, kLargeBufferSize, kEndOffset, kSmallBufferSize);
2428 }
2429 
2430 // Test zero-size copies
TEST_P(CopyTests_B2B,ZeroSizedCopy)2431 TEST_P(CopyTests_B2B, ZeroSizedCopy) {
2432     DoTest(kLargeBufferSize, 0, kLargeBufferSize, 0, 0);
2433     DoTest(kLargeBufferSize, 0, kLargeBufferSize, kLargeBufferSize, 0);
2434     DoTest(kLargeBufferSize, kLargeBufferSize, kLargeBufferSize, 0, 0);
2435     DoTest(kLargeBufferSize, kLargeBufferSize, kLargeBufferSize, kLargeBufferSize, 0);
2436 }
2437 
2438 DAWN_INSTANTIATE_TEST(CopyTests_B2B,
2439                       D3D12Backend(),
2440                       MetalBackend(),
2441                       OpenGLBackend(),
2442                       OpenGLESBackend(),
2443                       VulkanBackend());
2444 
2445 // Test clearing full buffers
TEST_P(ClearBufferTests,FullClear)2446 TEST_P(ClearBufferTests, FullClear) {
2447     DoTest(kSmallBufferSize, 0, kSmallBufferSize);
2448     DoTest(kLargeBufferSize, 0, kLargeBufferSize);
2449 }
2450 
2451 // Test clearing small pieces of a buffer at different corner case offsets
TEST_P(ClearBufferTests,SmallClearInBigBuffer)2452 TEST_P(ClearBufferTests, SmallClearInBigBuffer) {
2453     constexpr uint64_t kEndOffset = kLargeBufferSize - kSmallBufferSize;
2454     DoTest(kLargeBufferSize, 0, kSmallBufferSize);
2455     DoTest(kLargeBufferSize, kSmallBufferSize, kSmallBufferSize);
2456     DoTest(kLargeBufferSize, kEndOffset, kSmallBufferSize);
2457 }
2458 
2459 // Test zero-size clears
TEST_P(ClearBufferTests,ZeroSizedClear)2460 TEST_P(ClearBufferTests, ZeroSizedClear) {
2461     DoTest(kLargeBufferSize, 0, 0);
2462     DoTest(kLargeBufferSize, kSmallBufferSize, 0);
2463     DoTest(kLargeBufferSize, kLargeBufferSize, 0);
2464 }
2465 
2466 DAWN_INSTANTIATE_TEST(ClearBufferTests,
2467                       D3D12Backend(),
2468                       MetalBackend(),
2469                       OpenGLBackend(),
2470                       OpenGLESBackend(),
2471                       VulkanBackend());
2472