summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/tests/cts/checkout/src/webgpu/api/validation/render_pass/resolve.spec.ts
blob: c9a34c31578aea4ae038e3b3cc159b7845971e17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
export const description = `
Validation tests for render pass resolve.
`;

import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { GPUConst } from '../../../constants.js';
import { ValidationTest } from '../validation_test.js';

const kNumColorAttachments = 4;

export const g = makeTestGroup(ValidationTest);

g.test('resolve_attachment')
  .desc(
    `
Test various validation behaviors when a resolveTarget is provided.

- base case (valid).
- resolve source is not multisampled.
- resolve target is not single sampled.
- resolve target missing RENDER_ATTACHMENT usage.
- resolve target must have exactly one subresource:
    - base mip level {0, >0}, mip level count {1, >1}.
    - base array layer {0, >0}, array layer count {1, >1}.
- resolve target GPUTextureView is invalid
- resolve source and target have different formats.
    - rgba8unorm -> {bgra8unorm, rgba8unorm-srgb}
    - {bgra8unorm, rgba8unorm-srgb} -> rgba8unorm
    - test with other color attachments having a different format
- resolve source and target have different sizes.
`
  )
  .paramsSimple([
    // control case should be valid
    { _valid: true },
    // a single sampled resolve source should cause a validation error.
    { colorAttachmentSamples: 1, _valid: false },
    // a multisampled resolve target should cause a validation error.
    { resolveTargetSamples: 4, _valid: false },
    // resolveTargetUsage without RENDER_ATTACHMENT usage should cause a validation error.
    { resolveTargetUsage: GPUConst.TextureUsage.COPY_SRC, _valid: false },
    // non-zero resolve target base mip level should be valid.
    {
      resolveTargetViewBaseMipLevel: 1,
      resolveTargetHeight: 4,
      resolveTargetWidth: 4,
      _valid: true,
    },
    // a validation error should be created when resolveTarget is invalid.
    { resolveTargetInvalid: true, _valid: false },
    // a validation error should be created when mip count > 1
    { resolveTargetViewMipCount: 2, _valid: false },
    {
      resolveTargetViewBaseMipLevel: 1,
      resolveTargetViewMipCount: 2,
      resolveTargetHeight: 4,
      resolveTargetWidth: 4,
      _valid: false,
    },
    // non-zero resolve target base array layer should be valid.
    { resolveTargetViewBaseArrayLayer: 1, _valid: true },
    // a validation error should be created when array layer count > 1
    { resolveTargetViewArrayLayerCount: 2, _valid: false },
    { resolveTargetViewBaseArrayLayer: 1, resolveTargetViewArrayLayerCount: 2, _valid: false },
    // other color attachments resolving with a different format should be valid.
    { otherAttachmentFormat: 'bgra8unorm', _valid: true },
    // mismatched colorAttachment and resolveTarget formats should cause a validation error.
    { colorAttachmentFormat: 'bgra8unorm', _valid: false },
    { colorAttachmentFormat: 'rgba8unorm-srgb', _valid: false },
    { resolveTargetFormat: 'bgra8unorm', _valid: false },
    { resolveTargetFormat: 'rgba8unorm-srgb', _valid: false },
    // mismatched colorAttachment and resolveTarget sizes should cause a validation error.
    { colorAttachmentHeight: 4, _valid: false },
    { colorAttachmentWidth: 4, _valid: false },
    { resolveTargetHeight: 4, _valid: false },
    { resolveTargetWidth: 4, _valid: false },
  ] as const)
  .fn(async t => {
    const {
      colorAttachmentFormat = 'rgba8unorm',
      resolveTargetFormat = 'rgba8unorm',
      otherAttachmentFormat = 'rgba8unorm',
      colorAttachmentSamples = 4,
      resolveTargetSamples = 1,
      resolveTargetUsage = GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
      resolveTargetInvalid = false,
      resolveTargetViewMipCount = 1,
      resolveTargetViewBaseMipLevel = 0,
      resolveTargetViewArrayLayerCount = 1,
      resolveTargetViewBaseArrayLayer = 0,
      colorAttachmentHeight = 2,
      colorAttachmentWidth = 2,
      resolveTargetHeight = 2,
      resolveTargetWidth = 2,
      _valid,
    } = t.params;

    // Run the test in a nested loop such that the configured color attachment with resolve target
    // is tested while occupying each individual colorAttachment slot.
    for (let resolveSlot = 0; resolveSlot < kNumColorAttachments; resolveSlot++) {
      const renderPassColorAttachmentDescriptors: GPURenderPassColorAttachment[] = [];
      for (
        let colorAttachmentSlot = 0;
        colorAttachmentSlot < kNumColorAttachments;
        colorAttachmentSlot++
      ) {
        // resolveSlot === colorAttachmentSlot denotes the color attachment slot that contains the
        // color attachment with resolve target.
        if (resolveSlot === colorAttachmentSlot) {
          // Create the color attachment with resolve target with the configurable parameters.
          const resolveSourceColorAttachment = t.device.createTexture({
            format: colorAttachmentFormat,
            size: {
              width: colorAttachmentWidth,
              height: colorAttachmentHeight,
              depthOrArrayLayers: 1,
            },
            sampleCount: colorAttachmentSamples,
            usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
          });

          const resolveTarget = t.device.createTexture({
            format: resolveTargetFormat,
            size: {
              width: resolveTargetWidth,
              height: resolveTargetHeight,
              depthOrArrayLayers:
                resolveTargetViewBaseArrayLayer + resolveTargetViewArrayLayerCount,
            },
            sampleCount: resolveTargetSamples,
            mipLevelCount: resolveTargetViewBaseMipLevel + resolveTargetViewMipCount,
            usage: resolveTargetUsage,
          });

          renderPassColorAttachmentDescriptors.push({
            view: resolveSourceColorAttachment.createView(),
            loadOp: 'load',
            storeOp: 'discard',
            resolveTarget: resolveTargetInvalid
              ? t.getErrorTextureView()
              : resolveTarget.createView({
                  dimension: resolveTargetViewArrayLayerCount === 1 ? '2d' : '2d-array',
                  mipLevelCount: resolveTargetViewMipCount,
                  arrayLayerCount: resolveTargetViewArrayLayerCount,
                  baseMipLevel: resolveTargetViewBaseMipLevel,
                  baseArrayLayer: resolveTargetViewBaseArrayLayer,
                }),
          });
        } else {
          // Create a basic texture to fill other color attachment slots. This texture's dimensions
          // and sample count must match the resolve source color attachment to be valid.
          const colorAttachment = t.device.createTexture({
            format: otherAttachmentFormat,
            size: {
              width: colorAttachmentWidth,
              height: colorAttachmentHeight,
              depthOrArrayLayers: 1,
            },
            sampleCount: colorAttachmentSamples,
            usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
          });

          const resolveTarget = t.device.createTexture({
            format: otherAttachmentFormat,
            size: {
              width: colorAttachmentWidth,
              height: colorAttachmentHeight,
              depthOrArrayLayers: 1,
            },
            sampleCount: 1,
            usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
          });

          renderPassColorAttachmentDescriptors.push({
            view: colorAttachment.createView(),
            loadOp: 'load',
            storeOp: 'discard',
            resolveTarget: resolveTarget.createView(),
          });
        }
      }
      const encoder = t.device.createCommandEncoder();
      const pass = encoder.beginRenderPass({
        colorAttachments: renderPassColorAttachmentDescriptors,
      });
      pass.end();

      t.expectValidationError(() => {
        encoder.finish();
      }, !_valid);
    }
  });