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 <gtest/gtest.h>
16
17 #include "common/Assert.h"
18 #include "common/Constants.h"
19 #include "common/Math.h"
20 #include "dawn/webgpu_cpp_print.h"
21 #include "dawn_native/Format.h"
22 #include "dawn_native/d3d12/TextureCopySplitter.h"
23 #include "dawn_native/d3d12/d3d12_platform.h"
24 #include "utils/TestUtils.h"
25
26 using namespace dawn_native::d3d12;
27
28 namespace {
29
30 struct TextureSpec {
31 uint32_t x;
32 uint32_t y;
33 uint32_t z;
34 uint32_t width;
35 uint32_t height;
36 uint32_t depthOrArrayLayers;
37 uint32_t texelBlockSizeInBytes;
38 uint32_t blockWidth = 1;
39 uint32_t blockHeight = 1;
40 };
41
42 struct BufferSpec {
43 uint64_t offset;
44 uint32_t bytesPerRow;
45 uint32_t rowsPerImage;
46 };
47
48 // Check that each copy region fits inside the buffer footprint
ValidateFootprints(const TextureSpec & textureSpec,const BufferSpec & bufferSpec,const TextureCopySubresource & copySplit,wgpu::TextureDimension dimension)49 void ValidateFootprints(const TextureSpec& textureSpec,
50 const BufferSpec& bufferSpec,
51 const TextureCopySubresource& copySplit,
52 wgpu::TextureDimension dimension) {
53 for (uint32_t i = 0; i < copySplit.count; ++i) {
54 const auto& copy = copySplit.copies[i];
55 ASSERT_LE(copy.bufferOffset.x + copy.copySize.width, copy.bufferSize.width);
56 ASSERT_LE(copy.bufferOffset.y + copy.copySize.height, copy.bufferSize.height);
57 ASSERT_LE(copy.bufferOffset.z + copy.copySize.depthOrArrayLayers,
58 copy.bufferSize.depthOrArrayLayers);
59
60 // If there are multiple layers, 2D texture splitter actually splits each layer
61 // independently. See the details in Compute2DTextureCopySplits(). As a result,
62 // if we simply expand a copy region generated by 2D texture splitter to all
63 // layers, the copy region might be OOB. But that is not the approach that the current
64 // 2D texture splitter is doing, although Compute2DTextureCopySubresource forwards
65 // "copySize.depthOrArrayLayers" to the copy region it generated. So skip the test
66 // below for 2D textures with multiple layers.
67 if (textureSpec.depthOrArrayLayers <= 1 || dimension == wgpu::TextureDimension::e3D) {
68 uint32_t widthInBlocks = textureSpec.width / textureSpec.blockWidth;
69 uint32_t heightInBlocks = textureSpec.height / textureSpec.blockHeight;
70 uint64_t minimumRequiredBufferSize =
71 bufferSpec.offset +
72 utils::RequiredBytesInCopy(bufferSpec.bytesPerRow, bufferSpec.rowsPerImage,
73 widthInBlocks, heightInBlocks,
74 textureSpec.depthOrArrayLayers,
75 textureSpec.texelBlockSizeInBytes);
76
77 // The last pixel (buffer footprint) of each copy region depends on its bufferOffset
78 // and copySize. It is not the last pixel where the bufferSize ends.
79 ASSERT_EQ(copy.bufferOffset.x % textureSpec.blockWidth, 0u);
80 ASSERT_EQ(copy.copySize.width % textureSpec.blockWidth, 0u);
81 uint32_t footprintWidth = copy.bufferOffset.x + copy.copySize.width;
82 ASSERT_EQ(footprintWidth % textureSpec.blockWidth, 0u);
83 uint32_t footprintWidthInBlocks = footprintWidth / textureSpec.blockWidth;
84
85 ASSERT_EQ(copy.bufferOffset.y % textureSpec.blockHeight, 0u);
86 ASSERT_EQ(copy.copySize.height % textureSpec.blockHeight, 0u);
87 uint32_t footprintHeight = copy.bufferOffset.y + copy.copySize.height;
88 ASSERT_EQ(footprintHeight % textureSpec.blockHeight, 0u);
89 uint32_t footprintHeightInBlocks = footprintHeight / textureSpec.blockHeight;
90
91 uint64_t bufferSizeForFootprint =
92 copy.alignedOffset +
93 utils::RequiredBytesInCopy(bufferSpec.bytesPerRow, copy.bufferSize.height,
94 footprintWidthInBlocks, footprintHeightInBlocks,
95 copy.bufferSize.depthOrArrayLayers,
96 textureSpec.texelBlockSizeInBytes);
97
98 // The buffer footprint of each copy region should not exceed the minimum required
99 // buffer size. Otherwise, pixels accessed by copy may be OOB.
100 ASSERT_LE(bufferSizeForFootprint, minimumRequiredBufferSize);
101 }
102 }
103 }
104
105 // Check that the offset is aligned
ValidateOffset(const TextureCopySubresource & copySplit)106 void ValidateOffset(const TextureCopySubresource& copySplit) {
107 for (uint32_t i = 0; i < copySplit.count; ++i) {
108 ASSERT_TRUE(
109 Align(copySplit.copies[i].alignedOffset, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT) ==
110 copySplit.copies[i].alignedOffset);
111 }
112 }
113
InclusiveRangesOverlap(uint32_t minA,uint32_t maxA,uint32_t minB,uint32_t maxB)114 bool InclusiveRangesOverlap(uint32_t minA, uint32_t maxA, uint32_t minB, uint32_t maxB) {
115 return (minA <= minB && minB <= maxA) || (minB <= minA && minA <= maxB);
116 }
117
118 // Check that no pair of copy regions intersect each other
ValidateDisjoint(const TextureCopySubresource & copySplit)119 void ValidateDisjoint(const TextureCopySubresource& copySplit) {
120 for (uint32_t i = 0; i < copySplit.count; ++i) {
121 const auto& a = copySplit.copies[i];
122 for (uint32_t j = i + 1; j < copySplit.count; ++j) {
123 const auto& b = copySplit.copies[j];
124 // If textureOffset.x is 0, and copySize.width is 2, we are copying pixel 0 and
125 // 1. We never touch pixel 2 on x-axis. So the copied range on x-axis should be
126 // [textureOffset.x, textureOffset.x + copySize.width - 1] and both ends are
127 // included.
128 bool overlapX = InclusiveRangesOverlap(
129 a.textureOffset.x, a.textureOffset.x + a.copySize.width - 1, b.textureOffset.x,
130 b.textureOffset.x + b.copySize.width - 1);
131 bool overlapY = InclusiveRangesOverlap(
132 a.textureOffset.y, a.textureOffset.y + a.copySize.height - 1, b.textureOffset.y,
133 b.textureOffset.y + b.copySize.height - 1);
134 bool overlapZ = InclusiveRangesOverlap(
135 a.textureOffset.z, a.textureOffset.z + a.copySize.depthOrArrayLayers - 1,
136 b.textureOffset.z, b.textureOffset.z + b.copySize.depthOrArrayLayers - 1);
137 ASSERT_TRUE(!overlapX || !overlapY || !overlapZ);
138 }
139 }
140 }
141
142 // Check that the union of the copy regions exactly covers the texture region
ValidateTextureBounds(const TextureSpec & textureSpec,const TextureCopySubresource & copySplit)143 void ValidateTextureBounds(const TextureSpec& textureSpec,
144 const TextureCopySubresource& copySplit) {
145 ASSERT_TRUE(copySplit.count > 0);
146
147 uint32_t minX = copySplit.copies[0].textureOffset.x;
148 uint32_t minY = copySplit.copies[0].textureOffset.y;
149 uint32_t minZ = copySplit.copies[0].textureOffset.z;
150 uint32_t maxX = copySplit.copies[0].textureOffset.x + copySplit.copies[0].copySize.width;
151 uint32_t maxY = copySplit.copies[0].textureOffset.y + copySplit.copies[0].copySize.height;
152 uint32_t maxZ =
153 copySplit.copies[0].textureOffset.z + copySplit.copies[0].copySize.depthOrArrayLayers;
154
155 for (uint32_t i = 1; i < copySplit.count; ++i) {
156 const auto& copy = copySplit.copies[i];
157 minX = std::min(minX, copy.textureOffset.x);
158 minY = std::min(minY, copy.textureOffset.y);
159 minZ = std::min(minZ, copy.textureOffset.z);
160 maxX = std::max(maxX, copy.textureOffset.x + copy.copySize.width);
161 maxY = std::max(maxY, copy.textureOffset.y + copy.copySize.height);
162 maxZ = std::max(maxZ, copy.textureOffset.z + copy.copySize.depthOrArrayLayers);
163 }
164
165 ASSERT_EQ(minX, textureSpec.x);
166 ASSERT_EQ(minY, textureSpec.y);
167 ASSERT_EQ(minZ, textureSpec.z);
168 ASSERT_EQ(maxX, textureSpec.x + textureSpec.width);
169 ASSERT_EQ(maxY, textureSpec.y + textureSpec.height);
170 ASSERT_EQ(maxZ, textureSpec.z + textureSpec.depthOrArrayLayers);
171 }
172
173 // Validate that the number of pixels copied is exactly equal to the number of pixels in the
174 // texture region
ValidatePixelCount(const TextureSpec & textureSpec,const TextureCopySubresource & copySplit)175 void ValidatePixelCount(const TextureSpec& textureSpec,
176 const TextureCopySubresource& copySplit) {
177 uint32_t count = 0;
178 for (uint32_t i = 0; i < copySplit.count; ++i) {
179 const auto& copy = copySplit.copies[i];
180 uint32_t copiedPixels =
181 copy.copySize.width * copy.copySize.height * copy.copySize.depthOrArrayLayers;
182 ASSERT_GT(copiedPixels, 0u);
183 count += copiedPixels;
184 }
185 ASSERT_EQ(count, textureSpec.width * textureSpec.height * textureSpec.depthOrArrayLayers);
186 }
187
188 // Check that every buffer offset is at the correct pixel location
ValidateBufferOffset(const TextureSpec & textureSpec,const BufferSpec & bufferSpec,const TextureCopySubresource & copySplit,wgpu::TextureDimension dimension)189 void ValidateBufferOffset(const TextureSpec& textureSpec,
190 const BufferSpec& bufferSpec,
191 const TextureCopySubresource& copySplit,
192 wgpu::TextureDimension dimension) {
193 ASSERT_TRUE(copySplit.count > 0);
194
195 uint32_t texelsPerBlock = textureSpec.blockWidth * textureSpec.blockHeight;
196 for (uint32_t i = 0; i < copySplit.count; ++i) {
197 const auto& copy = copySplit.copies[i];
198
199 uint32_t bytesPerRowInTexels =
200 bufferSpec.bytesPerRow / textureSpec.texelBlockSizeInBytes * texelsPerBlock;
201 uint32_t slicePitchInTexels =
202 bytesPerRowInTexels * (bufferSpec.rowsPerImage / textureSpec.blockHeight);
203 uint32_t absoluteTexelOffset =
204 copy.alignedOffset / textureSpec.texelBlockSizeInBytes * texelsPerBlock +
205 copy.bufferOffset.x / textureSpec.blockWidth * texelsPerBlock +
206 copy.bufferOffset.y / textureSpec.blockHeight * bytesPerRowInTexels;
207
208 // There is one empty row at most in a 2D copy region. However, it is not true for
209 // a 3D texture copy region when we are copying the last row of each slice. We may
210 // need to offset a lot rows and copy.bufferOffset.y may be big.
211 if (dimension == wgpu::TextureDimension::e2D) {
212 ASSERT_LE(copy.bufferOffset.y, textureSpec.blockHeight);
213 }
214 ASSERT_EQ(copy.bufferOffset.z, 0u);
215
216 ASSERT_GE(absoluteTexelOffset,
217 bufferSpec.offset / textureSpec.texelBlockSizeInBytes * texelsPerBlock);
218 uint32_t relativeTexelOffset =
219 absoluteTexelOffset -
220 bufferSpec.offset / textureSpec.texelBlockSizeInBytes * texelsPerBlock;
221
222 uint32_t z = relativeTexelOffset / slicePitchInTexels;
223 uint32_t y = (relativeTexelOffset % slicePitchInTexels) / bytesPerRowInTexels;
224 uint32_t x = relativeTexelOffset % bytesPerRowInTexels;
225
226 ASSERT_EQ(copy.textureOffset.x - textureSpec.x, x);
227 ASSERT_EQ(copy.textureOffset.y - textureSpec.y, y);
228 ASSERT_EQ(copy.textureOffset.z - textureSpec.z, z);
229 }
230 }
231
ValidateCopySplit(const TextureSpec & textureSpec,const BufferSpec & bufferSpec,const TextureCopySubresource & copySplit,wgpu::TextureDimension dimension)232 void ValidateCopySplit(const TextureSpec& textureSpec,
233 const BufferSpec& bufferSpec,
234 const TextureCopySubresource& copySplit,
235 wgpu::TextureDimension dimension) {
236 ValidateFootprints(textureSpec, bufferSpec, copySplit, dimension);
237 ValidateOffset(copySplit);
238 ValidateDisjoint(copySplit);
239 ValidateTextureBounds(textureSpec, copySplit);
240 ValidatePixelCount(textureSpec, copySplit);
241 ValidateBufferOffset(textureSpec, bufferSpec, copySplit, dimension);
242 }
243
operator <<(std::ostream & os,const TextureSpec & textureSpec)244 std::ostream& operator<<(std::ostream& os, const TextureSpec& textureSpec) {
245 os << "TextureSpec("
246 << "[(" << textureSpec.x << ", " << textureSpec.y << ", " << textureSpec.z << "), ("
247 << textureSpec.width << ", " << textureSpec.height << ", "
248 << textureSpec.depthOrArrayLayers << ")], " << textureSpec.texelBlockSizeInBytes << ")";
249 return os;
250 }
251
operator <<(std::ostream & os,const BufferSpec & bufferSpec)252 std::ostream& operator<<(std::ostream& os, const BufferSpec& bufferSpec) {
253 os << "BufferSpec(" << bufferSpec.offset << ", " << bufferSpec.bytesPerRow << ", "
254 << bufferSpec.rowsPerImage << ")";
255 return os;
256 }
257
operator <<(std::ostream & os,const TextureCopySubresource & copySplit)258 std::ostream& operator<<(std::ostream& os, const TextureCopySubresource& copySplit) {
259 os << "CopySplit" << std::endl;
260 for (uint32_t i = 0; i < copySplit.count; ++i) {
261 const auto& copy = copySplit.copies[i];
262 os << " " << i << ": Texture at (" << copy.textureOffset.x << ", "
263 << copy.textureOffset.y << ", " << copy.textureOffset.z << "), size ("
264 << copy.copySize.width << ", " << copy.copySize.height << ", "
265 << copy.copySize.depthOrArrayLayers << ")" << std::endl;
266 os << " " << i << ": Buffer at (" << copy.bufferOffset.x << ", " << copy.bufferOffset.y
267 << ", " << copy.bufferOffset.z << "), footprint (" << copy.bufferSize.width << ", "
268 << copy.bufferSize.height << ", " << copy.bufferSize.depthOrArrayLayers << ")"
269 << std::endl;
270 }
271 return os;
272 }
273
274 // Define base texture sizes and offsets to test with: some aligned, some unaligned
275 constexpr TextureSpec kBaseTextureSpecs[] = {
276 {0, 0, 0, 1, 1, 1, 4},
277 {0, 0, 0, 64, 1, 1, 4},
278 {0, 0, 0, 128, 1, 1, 4},
279 {0, 0, 0, 192, 1, 1, 4},
280 {31, 16, 0, 1, 1, 1, 4},
281 {64, 16, 0, 1, 1, 1, 4},
282 {64, 16, 8, 1, 1, 1, 4},
283
284 {0, 0, 0, 64, 2, 1, 4},
285 {0, 0, 0, 64, 1, 2, 4},
286 {0, 0, 0, 64, 2, 2, 4},
287 {0, 0, 0, 128, 2, 1, 4},
288 {0, 0, 0, 128, 1, 2, 4},
289 {0, 0, 0, 128, 2, 2, 4},
290 {0, 0, 0, 192, 2, 1, 4},
291 {0, 0, 0, 192, 1, 2, 4},
292 {0, 0, 0, 192, 2, 2, 4},
293
294 {0, 0, 0, 1024, 1024, 1, 4},
295 {256, 512, 0, 1024, 1024, 1, 4},
296 {64, 48, 0, 1024, 1024, 1, 4},
297 {64, 48, 16, 1024, 1024, 1024, 4},
298
299 {0, 0, 0, 257, 31, 1, 4},
300 {0, 0, 0, 17, 93, 1, 4},
301 {59, 13, 0, 257, 31, 1, 4},
302 {17, 73, 0, 17, 93, 1, 4},
303 {17, 73, 59, 17, 93, 99, 4},
304
305 {0, 0, 0, 4, 4, 1, 8, 4, 4},
306 {64, 16, 0, 4, 4, 1, 8, 4, 4},
307 {64, 16, 8, 4, 4, 1, 8, 4, 4},
308 {0, 0, 0, 4, 4, 1, 16, 4, 4},
309 {64, 16, 0, 4, 4, 1, 16, 4, 4},
310 {64, 16, 8, 4, 4, 1, 16, 4, 4},
311
312 {0, 0, 0, 1024, 1024, 1, 8, 4, 4},
313 {256, 512, 0, 1024, 1024, 1, 8, 4, 4},
314 {64, 48, 0, 1024, 1024, 1, 8, 4, 4},
315 {64, 48, 16, 1024, 1024, 1, 8, 4, 4},
316 {0, 0, 0, 1024, 1024, 1, 16, 4, 4},
317 {256, 512, 0, 1024, 1024, 1, 16, 4, 4},
318 {64, 48, 0, 1024, 1024, 1, 4, 16, 4},
319 {64, 48, 16, 1024, 1024, 1, 16, 4, 4},
320 };
321
322 // Define base buffer sizes to work with: some offsets aligned, some unaligned. bytesPerRow is
323 // the minimum required
BaseBufferSpecs(const TextureSpec & textureSpec)324 std::array<BufferSpec, 15> BaseBufferSpecs(const TextureSpec& textureSpec) {
325 uint32_t bytesPerRow = Align(textureSpec.texelBlockSizeInBytes * textureSpec.width,
326 kTextureBytesPerRowAlignment);
327
328 auto alignNonPow2 = [](uint32_t value, uint32_t size) -> uint32_t {
329 return value == 0 ? 0 : ((value - 1) / size + 1) * size;
330 };
331
332 return {
333 BufferSpec{alignNonPow2(0, textureSpec.texelBlockSizeInBytes), bytesPerRow,
334 textureSpec.height},
335 BufferSpec{alignNonPow2(256, textureSpec.texelBlockSizeInBytes), bytesPerRow,
336 textureSpec.height},
337 BufferSpec{alignNonPow2(512, textureSpec.texelBlockSizeInBytes), bytesPerRow,
338 textureSpec.height},
339 BufferSpec{alignNonPow2(1024, textureSpec.texelBlockSizeInBytes), bytesPerRow,
340 textureSpec.height},
341 BufferSpec{alignNonPow2(1024, textureSpec.texelBlockSizeInBytes), bytesPerRow,
342 textureSpec.height * 2},
343
344 BufferSpec{alignNonPow2(32, textureSpec.texelBlockSizeInBytes), bytesPerRow,
345 textureSpec.height},
346 BufferSpec{alignNonPow2(64, textureSpec.texelBlockSizeInBytes), bytesPerRow,
347 textureSpec.height},
348 BufferSpec{alignNonPow2(64, textureSpec.texelBlockSizeInBytes), bytesPerRow,
349 textureSpec.height * 2},
350
351 BufferSpec{alignNonPow2(31, textureSpec.texelBlockSizeInBytes), bytesPerRow,
352 textureSpec.height},
353 BufferSpec{alignNonPow2(257, textureSpec.texelBlockSizeInBytes), bytesPerRow,
354 textureSpec.height},
355 BufferSpec{alignNonPow2(384, textureSpec.texelBlockSizeInBytes), bytesPerRow,
356 textureSpec.height},
357 BufferSpec{alignNonPow2(511, textureSpec.texelBlockSizeInBytes), bytesPerRow,
358 textureSpec.height},
359 BufferSpec{alignNonPow2(513, textureSpec.texelBlockSizeInBytes), bytesPerRow,
360 textureSpec.height},
361 BufferSpec{alignNonPow2(1023, textureSpec.texelBlockSizeInBytes), bytesPerRow,
362 textureSpec.height},
363 BufferSpec{alignNonPow2(1023, textureSpec.texelBlockSizeInBytes), bytesPerRow,
364 textureSpec.height * 2},
365 };
366 }
367
368 // Define a list of values to set properties in the spec structs
369 constexpr uint32_t kCheckValues[] = {1, 2, 3, 4, 5, 6, 7, 8, // small values
370 16, 32, 64, 128, 256, 512, 1024, 2048, // powers of 2
371 15, 31, 63, 127, 257, 511, 1023, 2047, // misalignments
372 17, 33, 65, 129, 257, 513, 1025, 2049};
373
374 } // namespace
375
376 class CopySplitTest : public testing::TestWithParam<wgpu::TextureDimension> {
377 protected:
DoTest(const TextureSpec & textureSpec,const BufferSpec & bufferSpec)378 void DoTest(const TextureSpec& textureSpec, const BufferSpec& bufferSpec) {
379 ASSERT(textureSpec.width % textureSpec.blockWidth == 0 &&
380 textureSpec.height % textureSpec.blockHeight == 0);
381
382 wgpu::TextureDimension dimension = GetParam();
383 TextureCopySubresource copySplit;
384 switch (dimension) {
385 case wgpu::TextureDimension::e2D: {
386 copySplit = Compute2DTextureCopySubresource(
387 {textureSpec.x, textureSpec.y, textureSpec.z},
388 {textureSpec.width, textureSpec.height, textureSpec.depthOrArrayLayers},
389 {textureSpec.texelBlockSizeInBytes, textureSpec.blockWidth,
390 textureSpec.blockHeight},
391 bufferSpec.offset, bufferSpec.bytesPerRow);
392 break;
393 }
394 case wgpu::TextureDimension::e3D: {
395 copySplit = Compute3DTextureCopySplits(
396 {textureSpec.x, textureSpec.y, textureSpec.z},
397 {textureSpec.width, textureSpec.height, textureSpec.depthOrArrayLayers},
398 {textureSpec.texelBlockSizeInBytes, textureSpec.blockWidth,
399 textureSpec.blockHeight},
400 bufferSpec.offset, bufferSpec.bytesPerRow, bufferSpec.rowsPerImage);
401 break;
402 }
403 default:
404 UNREACHABLE();
405 break;
406 }
407
408 ValidateCopySplit(textureSpec, bufferSpec, copySplit, dimension);
409
410 if (HasFatalFailure()) {
411 std::ostringstream message;
412 message << "Failed generating splits: " << textureSpec << ", " << bufferSpec
413 << std::endl
414 << dimension << " " << copySplit << std::endl;
415 FAIL() << message.str();
416 }
417 }
418 };
419
TEST_P(CopySplitTest,General)420 TEST_P(CopySplitTest, General) {
421 for (TextureSpec textureSpec : kBaseTextureSpecs) {
422 for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
423 DoTest(textureSpec, bufferSpec);
424 }
425 }
426 }
427
TEST_P(CopySplitTest,TextureWidth)428 TEST_P(CopySplitTest, TextureWidth) {
429 for (TextureSpec textureSpec : kBaseTextureSpecs) {
430 for (uint32_t val : kCheckValues) {
431 if (val % textureSpec.blockWidth != 0) {
432 continue;
433 }
434 textureSpec.width = val;
435 for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
436 DoTest(textureSpec, bufferSpec);
437 }
438 }
439 }
440 }
441
TEST_P(CopySplitTest,TextureHeight)442 TEST_P(CopySplitTest, TextureHeight) {
443 for (TextureSpec textureSpec : kBaseTextureSpecs) {
444 for (uint32_t val : kCheckValues) {
445 if (val % textureSpec.blockHeight != 0) {
446 continue;
447 }
448 textureSpec.height = val;
449 for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
450 DoTest(textureSpec, bufferSpec);
451 }
452 }
453 }
454 }
455
TEST_P(CopySplitTest,TextureX)456 TEST_P(CopySplitTest, TextureX) {
457 for (TextureSpec textureSpec : kBaseTextureSpecs) {
458 for (uint32_t val : kCheckValues) {
459 textureSpec.x = val;
460 for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
461 DoTest(textureSpec, bufferSpec);
462 }
463 }
464 }
465 }
466
TEST_P(CopySplitTest,TextureY)467 TEST_P(CopySplitTest, TextureY) {
468 for (TextureSpec textureSpec : kBaseTextureSpecs) {
469 for (uint32_t val : kCheckValues) {
470 textureSpec.y = val;
471 for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
472 DoTest(textureSpec, bufferSpec);
473 }
474 }
475 }
476 }
477
TEST_P(CopySplitTest,TexelSize)478 TEST_P(CopySplitTest, TexelSize) {
479 for (TextureSpec textureSpec : kBaseTextureSpecs) {
480 for (uint32_t texelSize : {4, 8, 16, 32, 64}) {
481 textureSpec.texelBlockSizeInBytes = texelSize;
482 for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
483 DoTest(textureSpec, bufferSpec);
484 }
485 }
486 }
487 }
488
TEST_P(CopySplitTest,BufferOffset)489 TEST_P(CopySplitTest, BufferOffset) {
490 for (TextureSpec textureSpec : kBaseTextureSpecs) {
491 for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
492 for (uint32_t val : kCheckValues) {
493 bufferSpec.offset = textureSpec.texelBlockSizeInBytes * val;
494
495 DoTest(textureSpec, bufferSpec);
496 }
497 }
498 }
499 }
500
TEST_P(CopySplitTest,RowPitch)501 TEST_P(CopySplitTest, RowPitch) {
502 for (TextureSpec textureSpec : kBaseTextureSpecs) {
503 for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
504 uint32_t baseRowPitch = bufferSpec.bytesPerRow;
505 for (uint32_t i = 0; i < 5; ++i) {
506 bufferSpec.bytesPerRow = baseRowPitch + i * 256;
507
508 DoTest(textureSpec, bufferSpec);
509 }
510 }
511 }
512 }
513
TEST_P(CopySplitTest,ImageHeight)514 TEST_P(CopySplitTest, ImageHeight) {
515 for (TextureSpec textureSpec : kBaseTextureSpecs) {
516 for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
517 uint32_t baseImageHeight = bufferSpec.rowsPerImage;
518 for (uint32_t i = 0; i < 5; ++i) {
519 bufferSpec.rowsPerImage = baseImageHeight + i * 256;
520
521 DoTest(textureSpec, bufferSpec);
522 }
523 }
524 }
525 }
526
527 INSTANTIATE_TEST_SUITE_P(,
528 CopySplitTest,
529 testing::Values(wgpu::TextureDimension::e2D, wgpu::TextureDimension::e3D));
530