Skip to content

Commit

Permalink
Merge branch 'main' into rotate
Browse files Browse the repository at this point in the history
  • Loading branch information
kainino0x authored Jan 7, 2025
2 parents 4bddbb2 + e99550b commit 75080e1
Show file tree
Hide file tree
Showing 17 changed files with 453 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
export const description = `
Tests that, in compat mode, you can not create a bind group layout with with
more than the max in stage limit even if the per stage limit is higher.
`;

import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { range } from '../../../../common/util/util.js';
import { RequiredLimitsTestMixin } from '../../../gpu_test.js';
import { CompatibilityTest } from '../../compatibility_test.js';

export const g = makeTestGroup(
RequiredLimitsTestMixin(CompatibilityTest, {
getRequiredLimits(adapter: GPUAdapter) {
return {
maxStorageBuffersInFragmentStage: adapter.limits.maxStorageBuffersInFragmentStage! / 2,
maxStorageBuffersInVertexStage: adapter.limits.maxStorageBuffersInVertexStage! / 2,
maxStorageBuffersPerShaderStage: adapter.limits.maxStorageBuffersPerShaderStage,
maxStorageTexturesInFragmentStage: adapter.limits.maxStorageTexturesInFragmentStage! / 2,
maxStorageTexturesInVertexStage: adapter.limits.maxStorageTexturesInVertexStage! / 2,
maxStorageTexturesPerShaderStage: adapter.limits.maxStorageTexturesPerShaderStage,
};
},
key() {
return `
maxStorageBuffersInFragmentStage/2,
maxStorageBuffersInVertexStage/2,
maxStorageTexturesInFragmentStage/2,
maxStorageTexturesInVertexStage/2,
maxStorageBuffersPerShaderStage
maxStorageTexturesPerShaderStage
`;
},
})
);

g.test('maxStorageBuffersTexturesInVertexFragmentStage')
.desc(
`
Tests that you can't use more than maxStorage(Buffers/Textures)In(Fragment/Vertex)Stage when
the limit is less than maxStorage(Buffers/Textures)PerShaderStage
`
)
.params(u =>
u
.combine('limit', [
'maxStorageBuffersInFragmentStage',
'maxStorageBuffersInVertexStage',
'maxStorageTexturesInFragmentStage',
'maxStorageTexturesInVertexStage',
] as const)
.beginSubcases()
.combine('extra', [0, 1] as const)
)
.fn(t => {
const { limit, extra } = t.params;
const { device } = t;

const isBuffer = limit.includes('Buffers');
const inStageLimit = device.limits[limit]!;
const perStageLimitName = isBuffer
? 'maxStorageBuffersPerShaderStage'
: 'maxStorageTexturesPerShaderStage';
const perStageLimit = device.limits[perStageLimitName];

t.debug(`${limit}(${inStageLimit}), ${perStageLimitName}(${perStageLimit})`);

t.skipIf(inStageLimit === 0, `${limit} is 0`);
t.skipIf(
!(inStageLimit < perStageLimit),
`${limit}(${inStageLimit}) is not less than ${perStageLimitName}(${perStageLimit})`
);

const visibility = limit.includes('Fragment') ? GPUShaderStage.FRAGMENT : GPUShaderStage.VERTEX;

const expectFailure = extra > 0;
t.expectValidationError(() => {
device.createBindGroupLayout({
entries: range(inStageLimit + extra, i => ({
binding: i,
visibility,
...(isBuffer
? { buffer: { type: 'read-only-storage' } }
: { storageTexture: { format: 'r32float', access: 'read-only' } }),
})),
});
}, expectFailure);
});
91 changes: 91 additions & 0 deletions src/webgpu/compat/api/validation/createPipelineLayout.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
export const description = `
Tests that, in compat mode, you can not create a pipeline layout with with
more than the max in stage limit even if the per stage limit is higher.
`;

import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { range } from '../../../../common/util/util.js';
import { RequiredLimitsTestMixin } from '../../../gpu_test.js';
import { CompatibilityTest } from '../../compatibility_test.js';

export const g = makeTestGroup(
RequiredLimitsTestMixin(CompatibilityTest, {
getRequiredLimits(adapter: GPUAdapter) {
return {
maxStorageBuffersInFragmentStage: adapter.limits.maxStorageBuffersInFragmentStage! / 2,
maxStorageBuffersInVertexStage: adapter.limits.maxStorageBuffersInVertexStage! / 2,
maxStorageBuffersPerShaderStage: adapter.limits.maxStorageBuffersPerShaderStage,
maxStorageTexturesInFragmentStage: adapter.limits.maxStorageTexturesInFragmentStage! / 2,
maxStorageTexturesInVertexStage: adapter.limits.maxStorageTexturesInVertexStage! / 2,
maxStorageTexturesPerShaderStage: adapter.limits.maxStorageTexturesPerShaderStage,
};
},
key() {
return `
maxStorageBuffersInFragmentStage/2,
maxStorageBuffersInVertexStage/2,
maxStorageTexturesInFragmentStage/2,
maxStorageTexturesInVertexStage/2,
maxStorageBuffersPerShaderStage
maxStorageTexturesPerShaderStage
`;
},
})
);

g.test('maxStorageBuffersTexturesInVertexFragmentStage')
.desc(
`
Tests that you can't use more than maxStorage(Buffers/Textures)In(Fragment/Vertex)Stage when
the limit is less than maxStorage(Buffers/Textures)PerShaderStage
`
)
.params(u =>
u
.combine('limit', [
'maxStorageBuffersInFragmentStage',
'maxStorageBuffersInVertexStage',
'maxStorageTexturesInFragmentStage',
'maxStorageTexturesInVertexStage',
] as const)
.beginSubcases()
.combine('extra', [0, 1] as const)
)
.fn(t => {
const { limit, extra } = t.params;
const { device } = t;

const isBuffer = limit.includes('Buffers');
const inStageLimit = device.limits[limit]!;
const perStageLimitName = isBuffer
? 'maxStorageBuffersPerShaderStage'
: 'maxStorageTexturesPerShaderStage';
const perStageLimit = device.limits[perStageLimitName];

t.debug(`{${limit}(${inStageLimit}), ${perStageLimitName}(${perStageLimit}})`);

t.skipIf(inStageLimit === 0, `${limit} is 0`);
t.skipIf(
!(inStageLimit < perStageLimit),
`{${limit}(${inStageLimit}) is not less than ${perStageLimitName}(${perStageLimit}})`
);

const visibility = limit.includes('Fragment') ? GPUShaderStage.FRAGMENT : GPUShaderStage.VERTEX;

const bindGroupLayouts = [inStageLimit, extra].map(count =>
device.createBindGroupLayout({
entries: range(count, i => ({
binding: i,
visibility,
...(isBuffer
? { buffer: { type: 'read-only-storage' } }
: { storageTexture: { format: 'r32float', access: 'read-only' } }),
})),
})
);

const expectFailure = extra > 0;
t.expectValidationError(() => {
device.createPipelineLayout({ bindGroupLayouts });
}, expectFailure);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
export const description = `
Tests that, in compat mode, you can not create a pipeline layout with with
more than the max in stage limit even if the per stage limit is higher.
`;

import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { range } from '../../../../../common/util/util.js';
import { RequiredLimitsTestMixin } from '../../../../gpu_test.js';
import { CompatibilityTest } from '../../../compatibility_test.js';

export const g = makeTestGroup(
RequiredLimitsTestMixin(CompatibilityTest, {
getRequiredLimits(adapter: GPUAdapter) {
return {
maxStorageBuffersInFragmentStage: adapter.limits.maxStorageBuffersInFragmentStage! / 2,
maxStorageBuffersInVertexStage: adapter.limits.maxStorageBuffersInVertexStage! / 2,
maxStorageBuffersPerShaderStage: adapter.limits.maxStorageBuffersPerShaderStage,
maxStorageTexturesInFragmentStage: adapter.limits.maxStorageTexturesInFragmentStage! / 2,
maxStorageTexturesInVertexStage: adapter.limits.maxStorageTexturesInVertexStage! / 2,
maxStorageTexturesPerShaderStage: adapter.limits.maxStorageTexturesPerShaderStage,
};
},
key() {
return `
maxStorageBuffersInFragmentStage/2,
maxStorageBuffersInVertexStage/2,
maxStorageTexturesInFragmentStage/2,
maxStorageTexturesInVertexStage/2,
maxStorageBuffersPerShaderStage
maxStorageTexturesPerShaderStage
`;
},
})
);

g.test('maxStorageBuffersTexturesInVertexFragmentStage')
.desc(
`
Tests that you can't use more than maxStorage(Buffers/Textures)In(Fragment/Vertex)Stage when
the limit is less than maxStorage(Buffers/Textures)PerShaderStage
`
)
.params(u =>
u
.combine('limit', [
'maxStorageBuffersInFragmentStage',
'maxStorageBuffersInVertexStage',
'maxStorageTexturesInFragmentStage',
'maxStorageTexturesInVertexStage',
] as const)
.beginSubcases()
.combine('async', [false, true] as const)
.combine('extra', [0, 1] as const)
)
.fn(t => {
const { limit, extra, async } = t.params;
const { device } = t;

const isBuffer = limit.includes('Buffers');
const inStageLimit = device.limits[limit]!;
const perStageLimitName = isBuffer
? 'maxStorageBuffersPerShaderStage'
: 'maxStorageTexturesPerShaderStage';
const perStageLimit = device.limits[perStageLimitName];

t.debug(`${limit}(${inStageLimit}), ${perStageLimitName}(${perStageLimit})`);

t.skipIf(inStageLimit === 0, `${limit} is 0`);
t.skipIf(
!(inStageLimit < perStageLimit),
`${limit}(${inStageLimit}) is not less than ${perStageLimitName}(${perStageLimit})`
);

const typeWGSLFn = isBuffer
? (i: number) => `var<storage, read> v${i}: f32;`
: (i: number) => `var v${i}: texture_storage_2d<r32float, read>;`;

const count = inStageLimit + extra;
const code = `
${range(count, i => `@group(0) @binding(${i}) ${typeWGSLFn(i)}`).join('\n')}
fn useResources() {
${range(count, i => `_ = v${i};`).join('\n')}
}
@vertex fn vsNoUse() -> @builtin(position) vec4f {
return vec4f(0);
}
@vertex fn vsUse() -> @builtin(position) vec4f {
useResources();
return vec4f(0);
}
@fragment fn fsNoUse() -> @location(0) vec4f {
return vec4f(0);
}
@fragment fn fsUse() -> @location(0) vec4f {
useResources();
return vec4f(0);
}
`;

const module = device.createShaderModule({ code });

const isFragment = limit.includes('Fragment');
const pipelineDescriptor: GPURenderPipelineDescriptor = {
layout: 'auto',
vertex: {
module,
entryPoint: isFragment ? 'vsNoUse' : 'vsUse',
},
fragment: {
module,
entryPoint: isFragment ? 'fsUse' : 'fsNoUse',
targets: [{ format: 'rgba8unorm' }],
},
};

const success = extra === 0;
t.doCreateRenderPipelineTest(async, success, pipelineDescriptor);
});
Loading

0 comments on commit 75080e1

Please sign in to comment.