Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] main from gpuweb:main #67

Merged
merged 3 commits into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/common/runtime/cmdline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ Options:
--coverage Emit coverage data.
--verbose Print result/log of every test as it runs.
--list Print all testcase names that match the given query and exit.
--list-unimplemented Print all unimplemented tests
--debug Include debug messages in logging.
--print-json Print the complete result JSON in the output.
--expectations Path to expectations file.
--gpu-provider Path to node module that provides the GPU implementation.
--gpu-provider-flag Flag to set on the gpu-provider as <flag>=<value>
--unroll-const-eval-loops Unrolls loops in constant-evaluation shader execution tests
--enforce-default-limits Enforce the default limits (note: powerPreference tests may fail)
--force-fallback-adapter Force a fallback adapter
--log-to-websocket Log to a websocket
--quiet Suppress summary information in output
`);
return sys.exit(rc);
Expand Down
3 changes: 3 additions & 0 deletions src/common/runtime/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ Options:
--gpu-provider Path to node module that provides the GPU implementation.
--gpu-provider-flag Flag to set on the gpu-provider as <flag>=<value>
--unroll-const-eval-loops Unrolls loops in constant-evaluation shader execution tests
--enforce-default-limits Enforce the default limits (note: powerPreference tests may fail)
--force-fallback-adapter Force a fallback adapter
--log-to-websocket Log to a websocket
--u Flag to set on the gpu-provider as <flag>=<value>

Provides an HTTP server used for running tests via an HTTP RPC interface
Expand Down
66 changes: 58 additions & 8 deletions src/webgpu/api/validation/capability_checks/limits/limit_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import {
getDefaultLimitsForAdapter,
kLimits,
} from '../../../../capability_info.js';
import { GPUConst } from '../../../../constants.js';
import { GPUTestBase } from '../../../../gpu_test.js';

type GPUSupportedLimit = keyof GPUSupportedLimits;
type GPUSupportedLimit = keyof Omit<GPUSupportedLimits, '__brand'>;

export const kCreatePipelineTypes = [
'createRenderPipeline',
Expand Down Expand Up @@ -52,14 +53,14 @@ export function getPipelineTypeForBindingCombination(bindingCombination: Binding
export function getStageVisibilityForBinidngCombination(bindingCombination: BindingCombination) {
switch (bindingCombination) {
case 'vertex':
return GPUShaderStage.VERTEX;
return GPUConst.ShaderStage.VERTEX;
case 'fragment':
return GPUShaderStage.FRAGMENT;
return GPUConst.ShaderStage.FRAGMENT;
case 'vertexAndFragmentWithPossibleVertexStageOverflow':
case 'vertexAndFragmentWithPossibleFragmentStageOverflow':
return GPUShaderStage.FRAGMENT | GPUShaderStage.VERTEX;
return GPUConst.ShaderStage.FRAGMENT | GPUConst.ShaderStage.VERTEX;
case 'compute':
return GPUShaderStage.COMPUTE;
return GPUConst.ShaderStage.COMPUTE;
}
}

Expand Down Expand Up @@ -245,7 +246,7 @@ export function getPerStageWGSLForBindingCombinationStorageTextures(

export const kLimitModes = ['defaultLimit', 'adapterLimit'] as const;
export type LimitMode = (typeof kLimitModes)[number];
export type LimitsRequest = Record<string, LimitMode>;
export type LimitsRequest = Record<string, LimitMode | number>;

export const kMaximumTestValues = ['atLimit', 'overLimit'] as const;
export type MaximumTestValue = (typeof kMaximumTestValues)[number];
Expand Down Expand Up @@ -338,6 +339,53 @@ export const kMinimumLimitBaseParams = kUnitCaseParamsBuilder
.combine('limitTest', kMinimumLimitValueTests)
.combine('testValueName', kMinimumTestValues);

/**
* Adds a maximum limit upto a dependent limit.
*
* Example:
* You want to test `maxStorageBuffersPerShaderStage` in fragment stage
* so you need `maxStorageBuffersInFragmentStage` set as well. But, you
* don't know exactly what value will be used for `maxStorageBuffersPerShaderStage`
* since that is defined by an enum like `underDefault`.
*
* So, you want `maxStorageBuffersInFragmentStage` to be set as high as possible.
* You can't just set it to it's maximum value (adapter.limits.maxStorageBuffersInFragmentStage)
* because if it's greater than `maxStorageBuffersPerShaderStage` you'll get an error.
*
* So, use this function
*
* const limits: LimitsRequest = {};
* addMaximumLimitUpToDependentLimit(
* adapter,
* limits,
* limit: 'maxStorageBuffersInFragmentStage', // the limit we want to add
* dependentLimitName: 'maxStorageBuffersPerShaderStage', // what the previous limit is dependent on
* dependentLimitTest: 'underDefault', // the enum used to decide the dependent limit
* )
*/
export function addMaximumLimitUpToDependentLimit(
adapter: GPUAdapter,
limits: LimitsRequest,
limit: GPUSupportedLimit,
dependentLimitName: GPUSupportedLimit,
dependentLimitTest: MaximumLimitValueTest
) {
if (!(limit in adapter.limits)) {
return;
}

const limitMaximum: number = adapter.limits[limit]!;
const dependentLimitMaximum: number = adapter.limits[dependentLimitName]!;
const testValue = getLimitValue(
getDefaultLimitForAdapter(adapter, dependentLimitName),
dependentLimitMaximum,
dependentLimitTest
);

const value = Math.min(testValue, dependentLimitMaximum, limitMaximum);
limits[limit] = value;
}

export class LimitTestsImpl extends GPUTestBase {
_adapter: GPUAdapter | null = null;
_device: GPUDevice | undefined = undefined;
Expand Down Expand Up @@ -415,11 +463,13 @@ export class LimitTestsImpl extends GPUTestBase {
requiredLimits[limit] = requestedLimit;

if (extraLimits) {
for (const [extraLimitStr, limitMode] of Object.entries(extraLimits)) {
for (const [extraLimitStr, limitModeOrNumber] of Object.entries(extraLimits)) {
const extraLimit = extraLimitStr as GPUSupportedLimit;
if (adapter.limits[extraLimit] !== undefined) {
requiredLimits[extraLimit] =
limitMode === 'defaultLimit'
typeof limitModeOrNumber === 'number'
? limitModeOrNumber
: limitModeOrNumber === 'defaultLimit'
? getDefaultLimitForAdapter(adapter, extraLimit)
: (adapter.limits[extraLimit] as number);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ import {
getPerStageWGSLForBindingCombination,
LimitsRequest,
getStageVisibilityForBinidngCombination,
addMaximumLimitUpToDependentLimit,
MaximumLimitValueTest,
} from './limit_utils.js';

const kExtraLimits: LimitsRequest = {
maxBindingsPerBindGroup: 'adapterLimit',
maxBindGroups: 'adapterLimit',
maxStorageBuffersInFragmentStage: 'adapterLimit',
maxStorageBuffersInVertexStage: 'adapterLimit',
};

const limit = 'maxStorageBuffersPerShaderStage';
Expand All @@ -49,6 +49,31 @@ function createBindGroupLayout(
return device.createBindGroupLayout(bindGroupLayoutDescription);
}

function addExtraRequiredLimits(
adapter: GPUAdapter,
limits: LimitsRequest,
limitTest: MaximumLimitValueTest
) {
const newLimits: LimitsRequest = { ...limits };

addMaximumLimitUpToDependentLimit(
adapter,
newLimits,
'maxStorageBuffersInFragmentStage',
limit,
limitTest
);
addMaximumLimitUpToDependentLimit(
adapter,
newLimits,
'maxStorageBuffersInVertexStage',
limit,
limitTest
);

return newLimits;
}

g.test('createBindGroupLayout,at_over')
.desc(
`
Expand Down Expand Up @@ -86,7 +111,7 @@ g.test('createBindGroupLayout,at_over')
createBindGroupLayout(device, visibility, type, order, testValue);
}, shouldError);
},
kExtraLimits
addExtraRequiredLimits(t.adapter, kExtraLimits, limitTest)
);
});

Expand Down Expand Up @@ -141,7 +166,7 @@ g.test('createPipelineLayout,at_over')
shouldError
);
},
kExtraLimits
addExtraRequiredLimits(t.adapter, kExtraLimits, limitTest)
);
});

Expand Down Expand Up @@ -197,6 +222,6 @@ g.test('createPipeline,at_over')
`actualLimit: ${actualLimit}, testValue: ${testValue}\n:${code}`
);
},
kExtraLimits
addExtraRequiredLimits(t.adapter, kExtraLimits, limitTest)
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ import {
LimitTestsImpl,
kBindingCombinations,
getStageVisibilityForBinidngCombination,
MaximumLimitValueTest,
addMaximumLimitUpToDependentLimit,
} from './limit_utils.js';

const kExtraLimits: LimitsRequest = {
maxBindingsPerBindGroup: 'adapterLimit',
maxBindGroups: 'adapterLimit',
maxStorageTexturesInFragmentStage: 'adapterLimit',
};

const limit = 'maxStorageTexturesPerShaderStage';
Expand Down Expand Up @@ -92,6 +93,37 @@ function skipIfAccessNotSupported(t: LimitTestsImpl, access: GPUStorageTextureAc
);
}

function filterWriteAccessInVertexStage(
visibility: GPUShaderStageFlags,
access: GPUStorageTextureAccess
) {
return access === 'read-only' || (visibility & GPUConst.ShaderStage.VERTEX) === 0;
}

function addExtraRequiredLimits(
adapter: GPUAdapter,
limits: LimitsRequest,
limitTest: MaximumLimitValueTest
) {
const newLimits: LimitsRequest = { ...limits };

addMaximumLimitUpToDependentLimit(
adapter,
newLimits,
'maxStorageTexturesInFragmentStage',
limit,
limitTest
);
addMaximumLimitUpToDependentLimit(
adapter,
newLimits,
'maxStorageTexturesInVertexStage',
limit,
limitTest
);

return newLimits;
}
g.test('createBindGroupLayout,at_over')
.desc(
`
Expand All @@ -105,6 +137,7 @@ g.test('createBindGroupLayout,at_over')
kMaximumLimitBaseParams
.combine('visibility', kShaderStageCombinationsWithStage)
.combine('access', kStorageTextureAccessValues)
.filter(t => filterWriteAccessInVertexStage(t.visibility, t.access))
.combine('order', kReorderOrderKeys)
)
.fn(async t => {
Expand All @@ -126,7 +159,7 @@ g.test('createBindGroupLayout,at_over')
shouldError
);
},
kExtraLimits
addExtraRequiredLimits(t.adapter, kExtraLimits, limitTest)
);
});

Expand All @@ -143,6 +176,7 @@ g.test('createPipelineLayout,at_over')
kMaximumLimitBaseParams
.combine('visibility', kShaderStageCombinationsWithStage)
.combine('access', kStorageTextureAccessValues)
.filter(t => filterWriteAccessInVertexStage(t.visibility, t.access))
.combine('order', kReorderOrderKeys)
)
.fn(async t => {
Expand Down Expand Up @@ -178,7 +212,7 @@ g.test('createPipelineLayout,at_over')
shouldError
);
},
kExtraLimits
addExtraRequiredLimits(t.adapter, kExtraLimits, limitTest)
);
});

Expand All @@ -196,6 +230,12 @@ g.test('createPipeline,at_over')
.combine('async', [false, true] as const)
.combine('bindingCombination', kBindingCombinations)
.combine('access', kStorageTextureAccessValues)
.filter(t =>
filterWriteAccessInVertexStage(
getStageVisibilityForBinidngCombination(t.bindingCombination),
t.access
)
)
.beginSubcases()
.combine('order', kReorderOrderKeys)
.combine('bindGroupTest', kBindGroupTests)
Expand Down Expand Up @@ -244,6 +284,6 @@ g.test('createPipeline,at_over')
`actualLimit: ${actualLimit}, testValue: ${testValue}\n:${code}`
);
},
kExtraLimits
addExtraRequiredLimits(t.adapter, kExtraLimits, limitTest)
);
});
2 changes: 1 addition & 1 deletion src/webgpu/print_environment.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ WPT disallows console.log and doesn't support logs on passing tests, so this doe

const info = JSON.stringify(
{
userAgent: navigator.userAgent,
userAgent: globalThis.navigator?.userAgent,
globalScope: Object.getPrototypeOf(globalThis).constructor.name,
globalTestConfig,
baseResourcePath: getResourcePath(''),
Expand Down
Loading