summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/tests/cts/checkout/src/webgpu/api/validation/encoding/beginRenderPass.spec.ts
blob: 388cdd69c03ee11fe52538bbbd06eda6bf2060bd (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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
export const description = `
Note: render pass 'occlusionQuerySet' validation is tested in queries/general.spec.ts

TODO: Check that depth-stencil attachment views must encompass all aspects.

TODO: check for duplication (render_pass/, etc.), plan, and implement.
Note possibly a lot of this should be operation tests instead.
Notes:
> - color attachments {zero, one, multiple}
>     - many different formats (some are non-renderable)
>     - is a view on a texture with multiple mip levels or array layers
>     - two attachments use the same view, or views of {intersecting, disjoint} ranges
>     - {without, with} resolve target
>         - resolve format compatibility with multisampled format
>     - {all possible load ops, load color {in range, negative, too large}}
>     - all possible store ops
> - depth/stencil attachment
>     - {unset, all possible formats}
>     - {all possible {depth, stencil} load ops, load values {in range, negative, too large}}
>     - all possible {depth, stencil} store ops
>     - depthReadOnly {t,f}, stencilReadOnly {t,f}
`;

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

export const g = makeTestGroup(ValidationTest);

g.test('color_attachments,device_mismatch')
  .desc(
    `
    Tests beginRenderPass cannot be called with color attachments whose texture view or resolve target is created from another device
    The 'view' and 'resolveTarget' are:
    - created from same device in ColorAttachment0 and ColorAttachment1
    - created from different device in ColorAttachment0 and ColorAttachment1
    - created from same device in ColorAttachment0, but from different device in ColorAttachment1
    `
  )
  .paramsSubcasesOnly([
    {
      view0Mismatched: false,
      target0Mismatched: false,
      view1Mismatched: false,
      target1Mismatched: false,
    }, // control case
    {
      view0Mismatched: false,
      target0Mismatched: true,
      view1Mismatched: false,
      target1Mismatched: true,
    },
    {
      view0Mismatched: true,
      target0Mismatched: false,
      view1Mismatched: true,
      target1Mismatched: false,
    },
    {
      view0Mismatched: false,
      target0Mismatched: false,
      view1Mismatched: false,
      target1Mismatched: true,
    },
  ])
  .beforeAllSubcases(t => {
    t.selectMismatchedDeviceOrSkipTestCase(undefined);
  })
  .fn(async t => {
    const { view0Mismatched, target0Mismatched, view1Mismatched, target1Mismatched } = t.params;
    const mismatched = view0Mismatched || target0Mismatched || view1Mismatched || target1Mismatched;

    const view0Texture = view0Mismatched
      ? t.getDeviceMismatchedRenderTexture(4)
      : t.getRenderTexture(4);
    const target0Texture = target0Mismatched
      ? t.getDeviceMismatchedRenderTexture()
      : t.getRenderTexture();
    const view1Texture = view1Mismatched
      ? t.getDeviceMismatchedRenderTexture(4)
      : t.getRenderTexture(4);
    const target1Texture = target1Mismatched
      ? t.getDeviceMismatchedRenderTexture()
      : t.getRenderTexture();

    const encoder = t.createEncoder('non-pass');
    const pass = encoder.encoder.beginRenderPass({
      colorAttachments: [
        {
          view: view0Texture.createView(),
          clearValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 },
          loadOp: 'clear',
          storeOp: 'store',
          resolveTarget: target0Texture.createView(),
        },
        {
          view: view1Texture.createView(),
          clearValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 },
          loadOp: 'clear',
          storeOp: 'store',
          resolveTarget: target1Texture.createView(),
        },
      ],
    });
    pass.end();

    encoder.validateFinish(!mismatched);
  });

g.test('depth_stencil_attachment,device_mismatch')
  .desc(
    'Tests beginRenderPass cannot be called with a depth stencil attachment whose texture view is created from another device'
  )
  .paramsSubcasesOnly(u => u.combine('mismatched', [true, false]))
  .beforeAllSubcases(t => {
    t.selectMismatchedDeviceOrSkipTestCase(undefined);
  })
  .fn(async t => {
    const { mismatched } = t.params;

    const descriptor: GPUTextureDescriptor = {
      size: { width: 4, height: 4, depthOrArrayLayers: 1 },
      format: 'depth24plus-stencil8',
      usage: GPUTextureUsage.RENDER_ATTACHMENT,
    };

    const depthStencilTexture = mismatched
      ? t.getDeviceMismatchedTexture(descriptor)
      : t.device.createTexture(descriptor);

    const encoder = t.createEncoder('non-pass');
    const pass = encoder.encoder.beginRenderPass({
      colorAttachments: [],
      depthStencilAttachment: {
        view: depthStencilTexture.createView(),
        depthClearValue: 0,
        depthLoadOp: 'clear',
        depthStoreOp: 'store',
        stencilClearValue: 0,
        stencilLoadOp: 'clear',
        stencilStoreOp: 'store',
      },
    });
    pass.end();

    encoder.validateFinish(!mismatched);
  });

g.test('occlusion_query_set,device_mismatch')
  .desc(
    'Tests beginRenderPass cannot be called with an occlusion query set created from another device'
  )
  .paramsSubcasesOnly(u => u.combine('mismatched', [true, false]))
  .beforeAllSubcases(t => {
    t.selectMismatchedDeviceOrSkipTestCase(undefined);
  })
  .fn(async t => {
    const { mismatched } = t.params;
    const sourceDevice = mismatched ? t.mismatchedDevice : t.device;

    const occlusionQuerySet = sourceDevice.createQuerySet({
      type: 'occlusion',
      count: 1,
    });
    t.trackForCleanup(occlusionQuerySet);

    const encoder = t.createEncoder('render pass', { occlusionQuerySet });
    encoder.validateFinish(!mismatched);
  });

g.test('timestamp_query_set,device_mismatch')
  .desc(
    `
  Tests beginRenderPass cannot be called with a timestamp query set created from another device.
  `
  )
  .paramsSubcasesOnly(u => u.combine('mismatched', [true, false]))
  .beforeAllSubcases(t => {
    t.selectDeviceOrSkipTestCase(['timestamp-query']);
    t.selectMismatchedDeviceOrSkipTestCase('timestamp-query');
  })
  .fn(async t => {
    const { mismatched } = t.params;
    const sourceDevice = mismatched ? t.mismatchedDevice : t.device;

    const timestampWrite = {
      querySet: sourceDevice.createQuerySet({ type: 'timestamp', count: 1 }),
      queryIndex: 0,
      location: 'beginning' as const,
    };

    const colorTexture = t.device.createTexture({
      format: 'rgba8unorm',
      size: { width: 4, height: 4, depthOrArrayLayers: 1 },
      usage: GPUTextureUsage.RENDER_ATTACHMENT,
    });

    const encoder = t.createEncoder('non-pass');
    const pass = encoder.encoder.beginRenderPass({
      colorAttachments: [
        {
          view: colorTexture.createView(),
          loadOp: 'load',
          storeOp: 'store',
        },
      ],
      timestampWrites: [timestampWrite],
    });
    pass.end();

    encoder.validateFinish(!mismatched);
  });