1export const description = `
2copyTextureToTexture tests.
3
4Test Plan: (TODO(jiawei.shao@intel.com): add tests on aspects and 1D/3D textures)
5* the source and destination texture
6  - the {source, destination} texture is {invalid, valid}.
7  - mipLevel {>, =, <} the mipmap level count of the {source, destination} texture.
8  - the source texture is created {with, without} GPUTextureUsage::CopySrc.
9  - the destination texture is created {with, without} GPUTextureUsage::CopyDst.
10* sample count
11  - the sample count of the source texture {is, isn't} equal to the one of the destination texture
12  - when the sample count is greater than 1:
13    - it {is, isn't} a copy of the whole subresource of the source texture.
14    - it {is, isn't} a copy of the whole subresource of the destination texture.
15* texture format
16  - the format of the source texture {is, isn't} equal to the one of the destination texture.
17    - including: depth24plus-stencil8 to/from {depth24plus, stencil8}.
18  - for each depth and/or stencil format: a copy between two textures with same format:
19    - it {is, isn't} a copy of the whole subresource of the {source, destination} texture.
20* copy ranges
21  - if the texture dimension is 2D:
22    - (srcOrigin.x + copyExtent.width) {>, =, <} the width of the subresource size of source
23      textureCopyView.
24    - (srcOrigin.y + copyExtent.height) {>, =, <} the height of the subresource size of source
25      textureCopyView.
26    - (srcOrigin.z + copyExtent.depth) {>, =, <} the depth of the subresource size of source
27      textureCopyView.
28    - (dstOrigin.x + copyExtent.width) {>, =, <} the width of the subresource size of destination
29      textureCopyView.
30    - (dstOrigin.y + copyExtent.height) {>, =, <} the height of the subresource size of destination
31      textureCopyView.
32    - (dstOrigin.z + copyExtent.depth) {>, =, <} the depth of the subresource size of destination
33      textureCopyView.
34* when the source and destination texture are the same one:
35  - the set of source texture subresources {has, doesn't have} overlaps with the one of destination
36    texture subresources.
37`;
38
39import { poptions, params } from '../../../common/framework/params_builder.js';
40import { makeTestGroup } from '../../../common/framework/test_group.js';
41import { assert } from '../../../common/framework/util/util.js';
42import {
43  kAllTextureFormatInfo,
44  kAllTextureFormats,
45  kCompressedTextureFormats,
46  kDepthStencilFormats,
47  kTextureUsages,
48} from '../../capability_info.js';
49import { align } from '../../util/math.js';
50
51import { ValidationTest } from './validation_test.js';
52
53class F extends ValidationTest {
54  TestCopyTextureToTexture(
55    source: GPUTextureCopyView,
56    destination: GPUTextureCopyView,
57    copySize: GPUExtent3D,
58    isSuccess: boolean
59  ): void {
60    const commandEncoder = this.device.createCommandEncoder();
61    commandEncoder.copyTextureToTexture(source, destination, copySize);
62
63    this.expectValidationError(() => {
64      commandEncoder.finish();
65    }, !isSuccess);
66  }
67
68  GetPhysicalSubresourceSize(
69    textureSize: GPUExtent3DDict,
70    format: GPUTextureFormat,
71    mipLevel: number
72  ): GPUExtent3DDict {
73    const virtualWidthAtLevel = Math.max(textureSize.width >> mipLevel, 1);
74    const virtualHeightAtLevel = Math.max(textureSize.height >> mipLevel, 1);
75    const physicalWidthAtLevel = align(
76      virtualWidthAtLevel,
77      kAllTextureFormatInfo[format].blockWidth
78    );
79    const physicalHeightAtLevel = align(
80      virtualHeightAtLevel,
81      kAllTextureFormatInfo[format].blockHeight
82    );
83    return { width: physicalWidthAtLevel, height: physicalHeightAtLevel, depth: textureSize.depth };
84  }
85}
86
87export const g = makeTestGroup(F);
88
89g.test('copy_with_invalid_texture').fn(async t => {
90  const validTexture = t.device.createTexture({
91    size: { width: 4, height: 4, depth: 1 },
92    format: 'rgba8unorm',
93    usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
94  });
95
96  const errorTexture = t.getErrorTexture();
97
98  t.TestCopyTextureToTexture(
99    { texture: errorTexture },
100    { texture: validTexture },
101    { width: 1, height: 1, depth: 1 },
102    false
103  );
104  t.TestCopyTextureToTexture(
105    { texture: validTexture },
106    { texture: errorTexture },
107    { width: 1, height: 1, depth: 1 },
108    false
109  );
110});
111
112g.test('mipmap_level')
113  .params([
114    { srcLevelCount: 1, dstLevelCount: 1, srcCopyLevel: 0, dstCopyLevel: 0 },
115    { srcLevelCount: 1, dstLevelCount: 1, srcCopyLevel: 1, dstCopyLevel: 0 },
116    { srcLevelCount: 1, dstLevelCount: 1, srcCopyLevel: 0, dstCopyLevel: 1 },
117    { srcLevelCount: 3, dstLevelCount: 3, srcCopyLevel: 0, dstCopyLevel: 0 },
118    { srcLevelCount: 3, dstLevelCount: 3, srcCopyLevel: 2, dstCopyLevel: 0 },
119    { srcLevelCount: 3, dstLevelCount: 3, srcCopyLevel: 3, dstCopyLevel: 0 },
120    { srcLevelCount: 3, dstLevelCount: 3, srcCopyLevel: 0, dstCopyLevel: 2 },
121    { srcLevelCount: 3, dstLevelCount: 3, srcCopyLevel: 0, dstCopyLevel: 3 },
122  ] as const)
123  .fn(async t => {
124    const { srcLevelCount, dstLevelCount, srcCopyLevel, dstCopyLevel } = t.params;
125
126    const srcTexture = t.device.createTexture({
127      size: { width: 32, height: 32, depth: 1 },
128      format: 'rgba8unorm',
129      usage: GPUTextureUsage.COPY_SRC,
130      mipLevelCount: srcLevelCount,
131    });
132    const dstTexture = t.device.createTexture({
133      size: { width: 32, height: 32, depth: 1 },
134      format: 'rgba8unorm',
135      usage: GPUTextureUsage.COPY_DST,
136      mipLevelCount: dstLevelCount,
137    });
138
139    const isSuccess = srcCopyLevel < srcLevelCount && dstCopyLevel < dstLevelCount;
140    t.TestCopyTextureToTexture(
141      { texture: srcTexture, mipLevel: srcCopyLevel },
142      { texture: dstTexture, mipLevel: dstCopyLevel },
143      { width: 1, height: 1, depth: 1 },
144      isSuccess
145    );
146  });
147
148g.test('texture_usage')
149  .params(
150    params()
151      .combine(poptions('srcUsage', kTextureUsages))
152      .combine(poptions('dstUsage', kTextureUsages))
153  )
154  .fn(async t => {
155    const { srcUsage, dstUsage } = t.params;
156
157    const srcTexture = t.device.createTexture({
158      size: { width: 4, height: 4, depth: 1 },
159      format: 'rgba8unorm',
160      usage: srcUsage,
161    });
162    const dstTexture = t.device.createTexture({
163      size: { width: 4, height: 4, depth: 1 },
164      format: 'rgba8unorm',
165      usage: dstUsage,
166    });
167
168    const isSuccess =
169      srcUsage === GPUTextureUsage.COPY_SRC && dstUsage === GPUTextureUsage.COPY_DST;
170
171    t.TestCopyTextureToTexture(
172      { texture: srcTexture },
173      { texture: dstTexture },
174      { width: 1, height: 1, depth: 1 },
175      isSuccess
176    );
177  });
178
179g.test('sample_count')
180  .params(
181    params()
182      .combine(poptions('srcSampleCount', [1, 4]))
183      .combine(poptions('dstSampleCount', [1, 4]))
184  )
185  .fn(async t => {
186    const { srcSampleCount, dstSampleCount } = t.params;
187
188    const srcTexture = t.device.createTexture({
189      size: { width: 4, height: 4, depth: 1 },
190      format: 'rgba8unorm',
191      usage: GPUTextureUsage.COPY_SRC,
192      sampleCount: srcSampleCount,
193    });
194    const dstTexture = t.device.createTexture({
195      size: { width: 4, height: 4, depth: 1 },
196      format: 'rgba8unorm',
197      usage: GPUTextureUsage.COPY_DST,
198      sampleCount: dstSampleCount,
199    });
200
201    const isSuccess = srcSampleCount === dstSampleCount;
202    t.TestCopyTextureToTexture(
203      { texture: srcTexture },
204      { texture: dstTexture },
205      { width: 4, height: 4, depth: 1 },
206      isSuccess
207    );
208  });
209
210g.test('multisampled_copy_restrictions')
211  .params(
212    params()
213      .combine(
214        poptions('srcCopyOrigin', [
215          { x: 0, y: 0, z: 0 },
216          { x: 1, y: 0, z: 0 },
217          { x: 0, y: 1, z: 0 },
218          { x: 1, y: 1, z: 0 },
219        ])
220      )
221      .combine(
222        poptions('dstCopyOrigin', [
223          { x: 0, y: 0, z: 0 },
224          { x: 1, y: 0, z: 0 },
225          { x: 0, y: 1, z: 0 },
226          { x: 1, y: 1, z: 0 },
227        ])
228      )
229      .expand(p => poptions('copyWidth', [32 - Math.max(p.srcCopyOrigin.x, p.dstCopyOrigin.x), 16]))
230      .expand(p => poptions('copyHeight', [16 - Math.max(p.srcCopyOrigin.y, p.dstCopyOrigin.y), 8]))
231  )
232  .fn(async t => {
233    const { srcCopyOrigin, dstCopyOrigin, copyWidth, copyHeight } = t.params;
234
235    const kWidth = 32;
236    const kHeight = 16;
237
238    // Currently we don't support multisampled 2D array textures and the mipmap level count of the
239    // multisampled textures must be 1.
240    const srcTexture = t.device.createTexture({
241      size: { width: kWidth, height: kHeight, depth: 1 },
242      format: 'rgba8unorm',
243      usage: GPUTextureUsage.COPY_SRC,
244      sampleCount: 4,
245    });
246    const dstTexture = t.device.createTexture({
247      size: { width: kWidth, height: kHeight, depth: 1 },
248      format: 'rgba8unorm',
249      usage: GPUTextureUsage.COPY_DST,
250      sampleCount: 4,
251    });
252
253    const isSuccess = copyWidth === kWidth && copyHeight === kHeight;
254    t.TestCopyTextureToTexture(
255      { texture: srcTexture, origin: srcCopyOrigin },
256      { texture: dstTexture, origin: dstCopyOrigin },
257      { width: copyWidth, height: copyHeight, depth: 1 },
258      isSuccess
259    );
260  });
261
262g.test('texture_format_equality')
263  .params(
264    params()
265      .combine(poptions('srcFormat', kAllTextureFormats))
266      .combine(poptions('dstFormat', kAllTextureFormats))
267  )
268  .fn(async t => {
269    const { srcFormat, dstFormat } = t.params;
270    const extensions: Array<GPUExtensionName> = [];
271
272    const srcFormatExtension = kAllTextureFormatInfo[srcFormat].extension;
273    if (srcFormatExtension !== undefined) {
274      extensions.push(srcFormatExtension);
275    }
276    const dstFormatExtension = kAllTextureFormatInfo[dstFormat].extension;
277    if (dstFormatExtension !== undefined) {
278      extensions.push(dstFormatExtension);
279    }
280
281    if (extensions.length) {
282      await t.selectDeviceOrSkipTestCase({ extensions });
283    }
284
285    const kTextureSize = { width: 16, height: 16, depth: 1 };
286
287    const srcTexture = t.device.createTexture({
288      size: kTextureSize,
289      format: srcFormat,
290      usage: GPUTextureUsage.COPY_SRC,
291    });
292
293    const dstTexture = t.device.createTexture({
294      size: kTextureSize,
295      format: dstFormat,
296      usage: GPUTextureUsage.COPY_DST,
297    });
298
299    const isSuccess = srcFormat === dstFormat;
300    t.TestCopyTextureToTexture(
301      { texture: srcTexture },
302      { texture: dstTexture },
303      kTextureSize,
304      isSuccess
305    );
306  });
307
308g.test('depth_stencil_copy_restrictions')
309  .params(
310    params()
311      .combine(poptions('format', kDepthStencilFormats))
312      .combine(
313        poptions('copyBoxOffsets', [
314          { x: 0, y: 0, width: 0, height: 0 },
315          { x: 1, y: 0, width: 0, height: 0 },
316          { x: 0, y: 1, width: 0, height: 0 },
317          { x: 0, y: 0, width: -1, height: 0 },
318          { x: 0, y: 0, width: 0, height: -1 },
319        ])
320      )
321      .combine(
322        poptions('srcTextureSize', [
323          { width: 64, height: 64, depth: 1 },
324          { width: 64, height: 32, depth: 1 },
325          { width: 32, height: 32, depth: 1 },
326        ])
327      )
328      .combine(
329        poptions('dstTextureSize', [
330          { width: 64, height: 64, depth: 1 },
331          { width: 64, height: 32, depth: 1 },
332          { width: 32, height: 32, depth: 1 },
333        ])
334      )
335      .combine(poptions('srcCopyLevel', [1, 2]))
336      .combine(poptions('dstCopyLevel', [0, 1]))
337  )
338  .fn(async t => {
339    const {
340      format,
341      copyBoxOffsets,
342      srcTextureSize,
343      dstTextureSize,
344      srcCopyLevel,
345      dstCopyLevel,
346    } = t.params;
347
348    const kMipLevelCount = 3;
349    const srcTexture = t.device.createTexture({
350      size: { width: srcTextureSize.width, height: srcTextureSize.height, depth: 1 },
351      format,
352      mipLevelCount: kMipLevelCount,
353      usage: GPUTextureUsage.COPY_SRC,
354    });
355    const dstTexture = t.device.createTexture({
356      size: { width: dstTextureSize.width, height: dstTextureSize.height, depth: 1 },
357      format,
358      mipLevelCount: kMipLevelCount,
359      usage: GPUTextureUsage.COPY_DST,
360    });
361
362    const srcSizeAtLevel = t.GetPhysicalSubresourceSize(srcTextureSize, format, srcCopyLevel);
363    const dstSizeAtLevel = t.GetPhysicalSubresourceSize(dstTextureSize, format, dstCopyLevel);
364
365    const copyOrigin = { x: copyBoxOffsets.x, y: copyBoxOffsets.y, z: 0 };
366
367    const copyWidth =
368      Math.min(srcSizeAtLevel.width, dstSizeAtLevel.width) + copyBoxOffsets.width - copyOrigin.x;
369    const copyHeight =
370      Math.min(srcSizeAtLevel.height, dstSizeAtLevel.height) + copyBoxOffsets.height - copyOrigin.y;
371
372    // Depth/stencil copies must copy whole subresources.
373    const isSuccess =
374      copyOrigin.x === 0 &&
375      copyOrigin.y === 0 &&
376      copyWidth === srcSizeAtLevel.width &&
377      copyHeight === srcSizeAtLevel.height &&
378      copyWidth === dstSizeAtLevel.width &&
379      copyHeight === dstSizeAtLevel.height;
380    t.TestCopyTextureToTexture(
381      { texture: srcTexture, origin: { x: 0, y: 0, z: 0 }, mipLevel: srcCopyLevel },
382      { texture: dstTexture, origin: copyOrigin, mipLevel: dstCopyLevel },
383      { width: copyWidth, height: copyHeight, depth: 1 },
384      isSuccess
385    );
386    t.TestCopyTextureToTexture(
387      { texture: srcTexture, origin: copyOrigin, mipLevel: srcCopyLevel },
388      { texture: dstTexture, origin: { x: 0, y: 0, z: 0 }, mipLevel: dstCopyLevel },
389      { width: copyWidth, height: copyHeight, depth: 1 },
390      isSuccess
391    );
392  });
393
394g.test('copy_ranges')
395  .params(
396    params()
397      .combine(
398        poptions('copyBoxOffsets', [
399          { x: 0, y: 0, z: 0, width: 0, height: 0, depth: -2 },
400          { x: 1, y: 0, z: 0, width: 0, height: 0, depth: -2 },
401          { x: 1, y: 0, z: 0, width: -1, height: 0, depth: -2 },
402          { x: 0, y: 1, z: 0, width: 0, height: 0, depth: -2 },
403          { x: 0, y: 1, z: 0, width: 0, height: -1, depth: -2 },
404          { x: 0, y: 0, z: 1, width: 0, height: 1, depth: -2 },
405          { x: 0, y: 0, z: 2, width: 0, height: 1, depth: 0 },
406          { x: 0, y: 0, z: 0, width: 1, height: 0, depth: -2 },
407          { x: 0, y: 0, z: 0, width: 0, height: 1, depth: -2 },
408          { x: 0, y: 0, z: 0, width: 0, height: 0, depth: 1 },
409          { x: 0, y: 0, z: 0, width: 0, height: 0, depth: 0 },
410          { x: 0, y: 0, z: 1, width: 0, height: 0, depth: -1 },
411          { x: 0, y: 0, z: 2, width: 0, height: 0, depth: -1 },
412        ])
413      )
414      .combine(poptions('srcCopyLevel', [0, 1, 3]))
415      .combine(poptions('dstCopyLevel', [0, 1, 3]))
416  )
417  .fn(async t => {
418    const { copyBoxOffsets, srcCopyLevel, dstCopyLevel } = t.params;
419
420    const kTextureSize = { width: 16, height: 8, depth: 3 };
421    const kMipLevelCount = 4;
422    const kFormat = 'rgba8unorm';
423
424    const srcTexture = t.device.createTexture({
425      size: kTextureSize,
426      format: kFormat,
427      mipLevelCount: kMipLevelCount,
428      usage: GPUTextureUsage.COPY_SRC,
429    });
430    const dstTexture = t.device.createTexture({
431      size: kTextureSize,
432      format: kFormat,
433      mipLevelCount: kMipLevelCount,
434      usage: GPUTextureUsage.COPY_DST,
435    });
436
437    const srcSizeAtLevel = t.GetPhysicalSubresourceSize(kTextureSize, kFormat, srcCopyLevel);
438    const dstSizeAtLevel = t.GetPhysicalSubresourceSize(kTextureSize, kFormat, dstCopyLevel);
439
440    const copyOrigin = { x: copyBoxOffsets.x, y: copyBoxOffsets.y, z: copyBoxOffsets.z };
441
442    const copyWidth = Math.max(
443      Math.min(srcSizeAtLevel.width, dstSizeAtLevel.width) + copyBoxOffsets.width - copyOrigin.x,
444      0
445    );
446    const copyHeight = Math.max(
447      Math.min(srcSizeAtLevel.height, dstSizeAtLevel.height) + copyBoxOffsets.height - copyOrigin.y,
448      0
449    );
450    const copyDepth = kTextureSize.depth + copyBoxOffsets.depth - copyOrigin.z;
451
452    {
453      const isSuccess =
454        copyWidth <= srcSizeAtLevel.width &&
455        copyHeight <= srcSizeAtLevel.height &&
456        copyOrigin.x + copyWidth <= dstSizeAtLevel.width &&
457        copyOrigin.y + copyHeight <= dstSizeAtLevel.height &&
458        copyOrigin.z + copyDepth <= kTextureSize.depth;
459
460      t.TestCopyTextureToTexture(
461        { texture: srcTexture, origin: { x: 0, y: 0, z: 0 }, mipLevel: srcCopyLevel },
462        { texture: dstTexture, origin: copyOrigin, mipLevel: dstCopyLevel },
463        { width: copyWidth, height: copyHeight, depth: copyDepth },
464        isSuccess
465      );
466    }
467
468    {
469      const isSuccess =
470        copyOrigin.x + copyWidth <= srcSizeAtLevel.width &&
471        copyOrigin.y + copyHeight <= srcSizeAtLevel.height &&
472        copyWidth <= dstSizeAtLevel.width &&
473        copyHeight <= dstSizeAtLevel.height &&
474        copyOrigin.z + copyDepth <= kTextureSize.depth;
475
476      t.TestCopyTextureToTexture(
477        { texture: srcTexture, origin: copyOrigin, mipLevel: srcCopyLevel },
478        { texture: dstTexture, origin: { x: 0, y: 0, z: 0 }, mipLevel: dstCopyLevel },
479        { width: copyWidth, height: copyHeight, depth: copyDepth },
480        isSuccess
481      );
482    }
483  });
484
485g.test('copy_within_same_texture')
486  .params(
487    params()
488      .combine(poptions('srcCopyOriginZ', [0, 2, 4]))
489      .combine(poptions('dstCopyOriginZ', [0, 2, 4]))
490      .combine(poptions('copyExtentDepth', [1, 2, 3]))
491  )
492  .fn(async t => {
493    const { srcCopyOriginZ, dstCopyOriginZ, copyExtentDepth } = t.params;
494
495    const kArrayLayerCount = 7;
496
497    const testTexture = t.device.createTexture({
498      size: { width: 16, height: 16, depth: kArrayLayerCount },
499      format: 'rgba8unorm',
500      usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
501    });
502
503    const isSuccess =
504      Math.min(srcCopyOriginZ, dstCopyOriginZ) + copyExtentDepth <=
505      Math.max(srcCopyOriginZ, dstCopyOriginZ);
506    t.TestCopyTextureToTexture(
507      { texture: testTexture, origin: { x: 0, y: 0, z: srcCopyOriginZ } },
508      { texture: testTexture, origin: { x: 0, y: 0, z: dstCopyOriginZ } },
509      { width: 16, height: 16, depth: copyExtentDepth },
510      isSuccess
511    );
512  });
513
514g.test('copy_ranges_with_compressed_texture_formats')
515  .params(
516    params()
517      .combine(poptions('format', kCompressedTextureFormats))
518      .combine(
519        poptions('copyBoxOffsets', [
520          { x: 0, y: 0, z: 0, width: 0, height: 0, depth: -2 },
521          { x: 1, y: 0, z: 0, width: 0, height: 0, depth: -2 },
522          { x: 4, y: 0, z: 0, width: 0, height: 0, depth: -2 },
523          { x: 0, y: 0, z: 0, width: -1, height: 0, depth: -2 },
524          { x: 0, y: 0, z: 0, width: -4, height: 0, depth: -2 },
525          { x: 0, y: 1, z: 0, width: 0, height: 0, depth: -2 },
526          { x: 0, y: 4, z: 0, width: 0, height: 0, depth: -2 },
527          { x: 0, y: 0, z: 0, width: 0, height: -1, depth: -2 },
528          { x: 0, y: 0, z: 0, width: 0, height: -4, depth: -2 },
529          { x: 0, y: 0, z: 0, width: 0, height: 0, depth: 0 },
530          { x: 0, y: 0, z: 1, width: 0, height: 0, depth: -1 },
531        ])
532      )
533      .combine(poptions('srcCopyLevel', [0, 1, 2]))
534      .combine(poptions('dstCopyLevel', [0, 1, 2]))
535  )
536  .fn(async t => {
537    const { format, copyBoxOffsets, srcCopyLevel, dstCopyLevel } = t.params;
538
539    const extension: GPUExtensionName | undefined = kAllTextureFormatInfo[format].extension;
540    assert(extension !== undefined);
541    await t.selectDeviceOrSkipTestCase({ extensions: [extension] });
542
543    const kTextureSize = { width: 60, height: 48, depth: 3 };
544    const kMipLevelCount = 4;
545
546    const srcTexture = t.device.createTexture({
547      size: kTextureSize,
548      format,
549      mipLevelCount: kMipLevelCount,
550      usage: GPUTextureUsage.COPY_SRC,
551    });
552    const dstTexture = t.device.createTexture({
553      size: kTextureSize,
554      format,
555      mipLevelCount: kMipLevelCount,
556      usage: GPUTextureUsage.COPY_DST,
557    });
558
559    const srcSizeAtLevel = t.GetPhysicalSubresourceSize(kTextureSize, format, srcCopyLevel);
560    const dstSizeAtLevel = t.GetPhysicalSubresourceSize(kTextureSize, format, dstCopyLevel);
561
562    const copyOrigin = { x: copyBoxOffsets.x, y: copyBoxOffsets.y, z: copyBoxOffsets.z };
563
564    const copyWidth = Math.max(
565      Math.min(srcSizeAtLevel.width, dstSizeAtLevel.width) + copyBoxOffsets.width - copyOrigin.x,
566      0
567    );
568    const copyHeight = Math.max(
569      Math.min(srcSizeAtLevel.height, dstSizeAtLevel.height) + copyBoxOffsets.height - copyOrigin.y,
570      0
571    );
572    const copyDepth = kTextureSize.depth + copyBoxOffsets.depth - copyOrigin.z;
573
574    const texelBlockWidth = kAllTextureFormatInfo[format].blockWidth;
575    const texelBlockHeight = kAllTextureFormatInfo[format].blockHeight;
576
577    const isSuccessForCompressedFormats =
578      copyOrigin.x % texelBlockWidth === 0 &&
579      copyOrigin.y % texelBlockHeight === 0 &&
580      copyWidth % texelBlockWidth === 0 &&
581      copyHeight % texelBlockHeight === 0;
582
583    {
584      const isSuccess =
585        isSuccessForCompressedFormats &&
586        copyWidth <= srcSizeAtLevel.width &&
587        copyHeight <= srcSizeAtLevel.height &&
588        copyOrigin.x + copyWidth <= dstSizeAtLevel.width &&
589        copyOrigin.y + copyHeight <= dstSizeAtLevel.height &&
590        copyOrigin.z + copyDepth <= kTextureSize.depth;
591
592      t.TestCopyTextureToTexture(
593        { texture: srcTexture, origin: { x: 0, y: 0, z: 0 }, mipLevel: srcCopyLevel },
594        { texture: dstTexture, origin: copyOrigin, mipLevel: dstCopyLevel },
595        { width: copyWidth, height: copyHeight, depth: copyDepth },
596        isSuccess
597      );
598    }
599
600    {
601      const isSuccess =
602        isSuccessForCompressedFormats &&
603        copyOrigin.x + copyWidth <= srcSizeAtLevel.width &&
604        copyOrigin.y + copyHeight <= srcSizeAtLevel.height &&
605        copyWidth <= dstSizeAtLevel.width &&
606        copyHeight <= dstSizeAtLevel.height &&
607        copyOrigin.z + copyDepth <= kTextureSize.depth;
608
609      t.TestCopyTextureToTexture(
610        { texture: srcTexture, origin: copyOrigin, mipLevel: srcCopyLevel },
611        { texture: dstTexture, origin: { x: 0, y: 0, z: 0 }, mipLevel: dstCopyLevel },
612        { width: copyWidth, height: copyHeight, depth: copyDepth },
613        isSuccess
614      );
615    }
616  });
617