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, ©Layout.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, ©Size);
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, ©Size);
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, ©Size);
427 } else {
428 encoder.CopyTextureToTextureInternal(&srcImageCopyTexture, &dstImageCopyTexture,
429 ©Size);
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, ©Size);
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, ©Size);
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