1export const description = `
2createPipelineLayout validation tests.
3`;
4
5import { poptions, params } from '../../../common/framework/params_builder.js';
6import { makeTestGroup } from '../../../common/framework/test_group.js';
7import { kBindingTypeInfo } from '../../capability_info.js';
8
9import { ValidationTest } from './validation_test.js';
10
11function clone<T extends GPUBindGroupLayoutDescriptor>(descriptor: T): T {
12  return JSON.parse(JSON.stringify(descriptor));
13}
14
15export const g = makeTestGroup(ValidationTest);
16
17g.test('number_of_dynamic_buffers_exceeds_the_maximum_value')
18  .params(
19    params()
20      .combine(poptions('visibility', [0, 2, 4, 6]))
21      .combine(
22        poptions('type', ['uniform-buffer', 'storage-buffer', 'readonly-storage-buffer'] as const)
23      )
24  )
25  .fn(async t => {
26    const { type, visibility } = t.params;
27    const { maxDynamic } = kBindingTypeInfo[type].perPipelineLimitClass;
28
29    const maxDynamicBufferBindings: GPUBindGroupLayoutEntry[] = [];
30    for (let binding = 0; binding < maxDynamic; binding++) {
31      maxDynamicBufferBindings.push({ binding, visibility, type, hasDynamicOffset: true });
32    }
33
34    const maxDynamicBufferBindGroupLayout = t.device.createBindGroupLayout({
35      entries: maxDynamicBufferBindings,
36    });
37
38    const goodDescriptor = {
39      entries: [{ binding: 0, visibility, type, hasDynamicOffset: false }],
40    };
41
42    const goodPipelineLayoutDescriptor = {
43      bindGroupLayouts: [
44        maxDynamicBufferBindGroupLayout,
45        t.device.createBindGroupLayout(goodDescriptor),
46      ],
47    };
48
49    // Control case
50    t.device.createPipelineLayout(goodPipelineLayoutDescriptor);
51
52    // Check dynamic buffers exceed maximum in pipeline layout.
53    const badDescriptor = clone(goodDescriptor);
54    badDescriptor.entries[0].hasDynamicOffset = true;
55
56    const badPipelineLayoutDescriptor = {
57      bindGroupLayouts: [
58        maxDynamicBufferBindGroupLayout,
59        t.device.createBindGroupLayout(badDescriptor),
60      ],
61    };
62
63    t.expectValidationError(() => {
64      t.device.createPipelineLayout(badPipelineLayoutDescriptor);
65    });
66  });
67
68g.test('number_of_bind_group_layouts_exceeds_the_maximum_value').fn(async t => {
69  const bindGroupLayoutDescriptor: GPUBindGroupLayoutDescriptor = {
70    entries: [],
71  };
72
73  // 4 is the maximum number of bind group layouts.
74  const maxBindGroupLayouts = [1, 2, 3, 4].map(() =>
75    t.device.createBindGroupLayout(bindGroupLayoutDescriptor)
76  );
77
78  const goodPipelineLayoutDescriptor = {
79    bindGroupLayouts: maxBindGroupLayouts,
80  };
81
82  // Control case
83  t.device.createPipelineLayout(goodPipelineLayoutDescriptor);
84
85  // Check bind group layouts exceed maximum in pipeline layout.
86  const badPipelineLayoutDescriptor = {
87    bindGroupLayouts: [
88      ...maxBindGroupLayouts,
89      t.device.createBindGroupLayout(bindGroupLayoutDescriptor),
90    ],
91  };
92
93  t.expectValidationError(() => {
94    t.device.createPipelineLayout(badPipelineLayoutDescriptor);
95  });
96});
97