diff --git a/src/common/runtime/helper/options.ts b/src/common/runtime/helper/options.ts index 2bea817d44a1..00cfb7ddc67a 100644 --- a/src/common/runtime/helper/options.ts +++ b/src/common/runtime/helper/options.ts @@ -100,7 +100,7 @@ export const kCTSOptionsInfo: OptionsInfos = { ], }, debug: { description: 'show more info' }, - compatibility: { description: 'run in compatibility mode' }, + compatibility: { description: 'request adapters with featureLevel: "compatibility"' }, forceFallbackAdapter: { description: 'pass forceFallbackAdapter: true to requestAdapter' }, enforceDefaultLimits: { description: `force the adapter limits to the default limits. diff --git a/src/resources/cache/hashes.json b/src/resources/cache/hashes.json index 7f214ed4d33b..594a41aa4d27 100644 --- a/src/resources/cache/hashes.json +++ b/src/resources/cache/hashes.json @@ -1,112 +1,112 @@ { - "webgpu/shader/execution/binary/af_addition.bin": "a076fefd", - "webgpu/shader/execution/binary/af_logical.bin": "5ef95b51", - "webgpu/shader/execution/binary/af_division.bin": "2ee1f517", - "webgpu/shader/execution/binary/af_matrix_addition.bin": "46d1c536", - "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "1ba9140b", - "webgpu/shader/execution/binary/af_multiplication.bin": "f55ec87f", - "webgpu/shader/execution/binary/af_remainder.bin": "39607546", - "webgpu/shader/execution/binary/af_subtraction.bin": "a1e1671b", - "webgpu/shader/execution/binary/f16_addition.bin": "98ec8cbb", - "webgpu/shader/execution/binary/f16_logical.bin": "e1b101aa", - "webgpu/shader/execution/binary/f16_division.bin": "f24f41e6", - "webgpu/shader/execution/binary/f16_matrix_addition.bin": "a6c126ba", - "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "4810437f", - "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "33bd4e0b", - "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "2a42a145", - "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "17eeecc2", - "webgpu/shader/execution/binary/f16_multiplication.bin": "5ee924d2", - "webgpu/shader/execution/binary/f16_remainder.bin": "a371e824", - "webgpu/shader/execution/binary/f16_subtraction.bin": "c5e6d455", - "webgpu/shader/execution/binary/f32_addition.bin": "371675d2", - "webgpu/shader/execution/binary/f32_logical.bin": "6c691798", - "webgpu/shader/execution/binary/f32_division.bin": "11ed1f8d", - "webgpu/shader/execution/binary/f32_matrix_addition.bin": "662a8c2a", - "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "3bef3e82", - "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "4b0d7b28", - "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "c1b78a5f", - "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "3ae5663c", - "webgpu/shader/execution/binary/f32_multiplication.bin": "7c887b3c", - "webgpu/shader/execution/binary/f32_remainder.bin": "955b27f7", - "webgpu/shader/execution/binary/f32_subtraction.bin": "10a5d990", - "webgpu/shader/execution/binary/i32_arithmetic.bin": "d8d24c51", - "webgpu/shader/execution/binary/i32_comparison.bin": "97a65e83", - "webgpu/shader/execution/binary/u32_arithmetic.bin": "76af97a5", - "webgpu/shader/execution/binary/u32_comparison.bin": "107ae7dd", - "webgpu/shader/execution/abs.bin": "8702bbde", - "webgpu/shader/execution/acos.bin": "505d4e5c", - "webgpu/shader/execution/acosh.bin": "6d849181", - "webgpu/shader/execution/asin.bin": "3739abaa", - "webgpu/shader/execution/asinh.bin": "5f912ea9", - "webgpu/shader/execution/atan.bin": "d15dc231", - "webgpu/shader/execution/atan2.bin": "60eb6015", - "webgpu/shader/execution/atanh.bin": "f8b2fb79", - "webgpu/shader/execution/bitcast.bin": "af41ce05", - "webgpu/shader/execution/ceil.bin": "8da53d8b", - "webgpu/shader/execution/clamp.bin": "a02c15b", - "webgpu/shader/execution/cos.bin": "4f444ab6", - "webgpu/shader/execution/cosh.bin": "aaa40c4b", - "webgpu/shader/execution/cross.bin": "534a949c", - "webgpu/shader/execution/degrees.bin": "2d55f678", - "webgpu/shader/execution/determinant.bin": "5b49ee94", - "webgpu/shader/execution/distance.bin": "d6963680", - "webgpu/shader/execution/dot.bin": "e03347d6", - "webgpu/shader/execution/exp.bin": "a5affb43", - "webgpu/shader/execution/exp2.bin": "21d376a0", - "webgpu/shader/execution/faceForward.bin": "e0e2ad0e", - "webgpu/shader/execution/floor.bin": "3658073", - "webgpu/shader/execution/fma.bin": "a7cc5707", - "webgpu/shader/execution/fract.bin": "44a3775d", - "webgpu/shader/execution/frexp.bin": "241abedb", - "webgpu/shader/execution/inverseSqrt.bin": "766974b5", - "webgpu/shader/execution/ldexp.bin": "db0c0fcf", - "webgpu/shader/execution/length.bin": "c1240c03", - "webgpu/shader/execution/log.bin": "98aceda7", - "webgpu/shader/execution/log2.bin": "ffdc85d7", - "webgpu/shader/execution/max.bin": "a2c6c4b1", - "webgpu/shader/execution/min.bin": "344390ef", - "webgpu/shader/execution/mix.bin": "367c1ff3", - "webgpu/shader/execution/modf.bin": "7be6faa3", - "webgpu/shader/execution/normalize.bin": "b2b9eb0c", - "webgpu/shader/execution/pack2x16float.bin": "a66da753", - "webgpu/shader/execution/pow.bin": "a9858b9", - "webgpu/shader/execution/quantizeToF16.bin": "bf80d34e", - "webgpu/shader/execution/radians.bin": "cc7b8d0c", - "webgpu/shader/execution/reflect.bin": "cb0be6ee", - "webgpu/shader/execution/refract.bin": "501ac731", - "webgpu/shader/execution/round.bin": "b4ea1e61", - "webgpu/shader/execution/saturate.bin": "2783de66", - "webgpu/shader/execution/sign.bin": "30ad6ecf", - "webgpu/shader/execution/sin.bin": "9f8b5d9e", - "webgpu/shader/execution/sinh.bin": "d988cc09", - "webgpu/shader/execution/smoothstep.bin": "2e89af8e", - "webgpu/shader/execution/sqrt.bin": "55dd81cf", - "webgpu/shader/execution/step.bin": "f1bced79", - "webgpu/shader/execution/tan.bin": "a8354079", - "webgpu/shader/execution/tanh.bin": "fd1c38ee", - "webgpu/shader/execution/transpose.bin": "e8bdca54", - "webgpu/shader/execution/trunc.bin": "ffedffa", - "webgpu/shader/execution/unpack2x16float.bin": "9251ad61", - "webgpu/shader/execution/unpack2x16snorm.bin": "6133b78b", - "webgpu/shader/execution/unpack2x16unorm.bin": "291b47bd", - "webgpu/shader/execution/unpack4x8snorm.bin": "93230ee1", - "webgpu/shader/execution/unpack4x8unorm.bin": "99fd9a23", - "webgpu/shader/execution/unary/af_arithmetic.bin": "dc1de35b", - "webgpu/shader/execution/unary/af_assignment.bin": "6a907068", - "webgpu/shader/execution/unary/bool_conversion.bin": "4fb09ad6", - "webgpu/shader/execution/unary/f16_arithmetic.bin": "5443808d", - "webgpu/shader/execution/unary/f16_conversion.bin": "e6f6743", - "webgpu/shader/execution/unary/f32_arithmetic.bin": "980abd9d", - "webgpu/shader/execution/unary/f32_conversion.bin": "c666a6e8", - "webgpu/shader/execution/unary/i32_arithmetic.bin": "4c1bf2ef", - "webgpu/shader/execution/unary/i32_conversion.bin": "9d2e1411", - "webgpu/shader/execution/unary/u32_conversion.bin": "962b68ac", - "webgpu/shader/execution/unary/ai_assignment.bin": "d34f3811", - "webgpu/shader/execution/binary/ai_arithmetic.bin": "b4811a5c", - "webgpu/shader/execution/unary/ai_arithmetic.bin": "d203a070", - "webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin": "1405c422", - "webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin": "c24e7f75", - "webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin": "e36fcfd", - "webgpu/shader/execution/derivatives.bin": "e8c5ea73", - "webgpu/shader/execution/fwidth.bin": "cb050a6f" + "webgpu/shader/execution/binary/af_addition.bin": "a82ac4de", + "webgpu/shader/execution/binary/af_logical.bin": "73364bc2", + "webgpu/shader/execution/binary/af_division.bin": "40fd4e4a", + "webgpu/shader/execution/binary/af_matrix_addition.bin": "b8a7b3d6", + "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "4b18333d", + "webgpu/shader/execution/binary/af_multiplication.bin": "6f8d9b5b", + "webgpu/shader/execution/binary/af_remainder.bin": "a19a50e7", + "webgpu/shader/execution/binary/af_subtraction.bin": "ea6023c9", + "webgpu/shader/execution/binary/f16_addition.bin": "d53f1d97", + "webgpu/shader/execution/binary/f16_logical.bin": "d8be1f65", + "webgpu/shader/execution/binary/f16_division.bin": "37c31939", + "webgpu/shader/execution/binary/f16_matrix_addition.bin": "c16895d3", + "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "c67ec845", + "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "a1abb931", + "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "688153d4", + "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "97265449", + "webgpu/shader/execution/binary/f16_multiplication.bin": "119d4bdb", + "webgpu/shader/execution/binary/f16_remainder.bin": "1648ca32", + "webgpu/shader/execution/binary/f16_subtraction.bin": "ad42f5f9", + "webgpu/shader/execution/binary/f32_addition.bin": "d67ba1f0", + "webgpu/shader/execution/binary/f32_logical.bin": "9a797387", + "webgpu/shader/execution/binary/f32_division.bin": "40d3008f", + "webgpu/shader/execution/binary/f32_matrix_addition.bin": "c55b4a06", + "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "4d64d302", + "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "e402c845", + "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "826cad08", + "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "64993a34", + "webgpu/shader/execution/binary/f32_multiplication.bin": "4cfa9938", + "webgpu/shader/execution/binary/f32_remainder.bin": "5059bf7", + "webgpu/shader/execution/binary/f32_subtraction.bin": "58da64ed", + "webgpu/shader/execution/binary/i32_arithmetic.bin": "9b4cda42", + "webgpu/shader/execution/binary/i32_comparison.bin": "1ca385cc", + "webgpu/shader/execution/binary/u32_arithmetic.bin": "e46139a5", + "webgpu/shader/execution/binary/u32_comparison.bin": "8fcac433", + "webgpu/shader/execution/abs.bin": "153850ad", + "webgpu/shader/execution/acos.bin": "2985fb9f", + "webgpu/shader/execution/acosh.bin": "b787f8eb", + "webgpu/shader/execution/asin.bin": "e14eb685", + "webgpu/shader/execution/asinh.bin": "8b456dd1", + "webgpu/shader/execution/atan.bin": "eead86e4", + "webgpu/shader/execution/atan2.bin": "bc0f6797", + "webgpu/shader/execution/atanh.bin": "d18d533", + "webgpu/shader/execution/bitcast.bin": "78c46c4", + "webgpu/shader/execution/ceil.bin": "c1863837", + "webgpu/shader/execution/clamp.bin": "688410eb", + "webgpu/shader/execution/cos.bin": "668268e6", + "webgpu/shader/execution/cosh.bin": "c5efe6b2", + "webgpu/shader/execution/cross.bin": "cd57f366", + "webgpu/shader/execution/degrees.bin": "8cbdc472", + "webgpu/shader/execution/determinant.bin": "63d946dd", + "webgpu/shader/execution/distance.bin": "51a23187", + "webgpu/shader/execution/dot.bin": "9d77991", + "webgpu/shader/execution/exp.bin": "7399ce3", + "webgpu/shader/execution/exp2.bin": "2fa51810", + "webgpu/shader/execution/faceForward.bin": "23777867", + "webgpu/shader/execution/floor.bin": "3255b154", + "webgpu/shader/execution/fma.bin": "d6c70a08", + "webgpu/shader/execution/fract.bin": "8395ea7", + "webgpu/shader/execution/frexp.bin": "f0d32d7c", + "webgpu/shader/execution/inverseSqrt.bin": "815cc5fa", + "webgpu/shader/execution/ldexp.bin": "f8bc4718", + "webgpu/shader/execution/length.bin": "aa52e8d", + "webgpu/shader/execution/log.bin": "d4bd78f", + "webgpu/shader/execution/log2.bin": "e9c2855", + "webgpu/shader/execution/max.bin": "ed04a2a5", + "webgpu/shader/execution/min.bin": "5662df47", + "webgpu/shader/execution/mix.bin": "ec516f82", + "webgpu/shader/execution/modf.bin": "5055026c", + "webgpu/shader/execution/normalize.bin": "7938c982", + "webgpu/shader/execution/pack2x16float.bin": "86d296f7", + "webgpu/shader/execution/pow.bin": "f08da592", + "webgpu/shader/execution/quantizeToF16.bin": "6804f2d7", + "webgpu/shader/execution/radians.bin": "9e9624a4", + "webgpu/shader/execution/reflect.bin": "4b76785c", + "webgpu/shader/execution/refract.bin": "fc13970c", + "webgpu/shader/execution/round.bin": "50795876", + "webgpu/shader/execution/saturate.bin": "c277428e", + "webgpu/shader/execution/sign.bin": "5e8fe9bf", + "webgpu/shader/execution/sin.bin": "80eb708e", + "webgpu/shader/execution/sinh.bin": "e41f0c64", + "webgpu/shader/execution/smoothstep.bin": "8ba929f5", + "webgpu/shader/execution/sqrt.bin": "f92bc382", + "webgpu/shader/execution/step.bin": "50d7aa5f", + "webgpu/shader/execution/tan.bin": "4ee5d198", + "webgpu/shader/execution/tanh.bin": "369d1a60", + "webgpu/shader/execution/transpose.bin": "d1e2be48", + "webgpu/shader/execution/trunc.bin": "7301f9c3", + "webgpu/shader/execution/unpack2x16float.bin": "3e77cb78", + "webgpu/shader/execution/unpack2x16snorm.bin": "7bd81df4", + "webgpu/shader/execution/unpack2x16unorm.bin": "5af34849", + "webgpu/shader/execution/unpack4x8snorm.bin": "128ec462", + "webgpu/shader/execution/unpack4x8unorm.bin": "4bd7dc1", + "webgpu/shader/execution/unary/af_arithmetic.bin": "728b0df2", + "webgpu/shader/execution/unary/af_assignment.bin": "bcfc32c", + "webgpu/shader/execution/unary/bool_conversion.bin": "bec92a25", + "webgpu/shader/execution/unary/f16_arithmetic.bin": "cb76d0ef", + "webgpu/shader/execution/unary/f16_conversion.bin": "2d5d1f08", + "webgpu/shader/execution/unary/f32_arithmetic.bin": "1a99657e", + "webgpu/shader/execution/unary/f32_conversion.bin": "d6abb886", + "webgpu/shader/execution/unary/i32_arithmetic.bin": "e8b56bb6", + "webgpu/shader/execution/unary/i32_conversion.bin": "d95802e4", + "webgpu/shader/execution/unary/u32_conversion.bin": "1365e709", + "webgpu/shader/execution/unary/ai_assignment.bin": "b1d26a5b", + "webgpu/shader/execution/binary/ai_arithmetic.bin": "119e5673", + "webgpu/shader/execution/unary/ai_arithmetic.bin": "16872943", + "webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin": "4fdf8a9", + "webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin": "9797bab", + "webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin": "fed0596f", + "webgpu/shader/execution/derivatives.bin": "4c2dfba5", + "webgpu/shader/execution/fwidth.bin": "c4b1751b" } \ No newline at end of file diff --git a/src/webgpu/api/operation/command_buffer/programmable/programmable_state_test.ts b/src/webgpu/api/operation/command_buffer/programmable/programmable_state_test.ts index 19cf91419c16..a8222807b7bd 100644 --- a/src/webgpu/api/operation/command_buffer/programmable/programmable_state_test.ts +++ b/src/webgpu/api/operation/command_buffer/programmable/programmable_state_test.ts @@ -1,5 +1,5 @@ import { unreachable } from '../../../../../common/util/util.js'; -import { GPUTest } from '../../../../gpu_test.js'; +import { GPUTest, GPUTestBase } from '../../../../gpu_test.js'; import { EncoderType } from '../../../../util/command_buffer_maker.js'; interface BindGroupIndices { @@ -8,38 +8,81 @@ interface BindGroupIndices { out: number; } +type CreateEncoderType = ReturnType< + typeof GPUTestBase.prototype.createEncoder<'compute pass' | 'render pass' | 'render bundle'> +>['encoder']; + export class ProgrammableStateTest extends GPUTest { private commonBindGroupLayouts: Map = new Map(); - getBindGroupLayout(type: GPUBufferBindingType): GPUBindGroupLayout { - if (!this.commonBindGroupLayouts.has(type)) { + skipIfNeedsStorageBuffersInFragmentStageAndHaveNone( + type: GPUBufferBindingType, + encoderType: EncoderType + ) { + if (!this.isCompatibility) { + return; + } + + const needsStorageBuffersInFragmentStage = + type === 'storage' && (encoderType === 'render bundle' || encoderType === 'render pass'); + + this.skipIf( + needsStorageBuffersInFragmentStage && + !(this.device.limits.maxStorageBuffersInFragmentStage! >= 3), + `maxStorageBuffersInFragmentStage(${this.device.limits.maxStorageBuffersInFragmentStage}) < 3` + ); + } + + getBindGroupLayout( + type: GPUBufferBindingType, + visibility: GPUShaderStageFlags + ): GPUBindGroupLayout { + const id = `${type}:${visibility}`; + if (!this.commonBindGroupLayouts.has(id)) { this.commonBindGroupLayouts.set( - type, + id, this.device.createBindGroupLayout({ entries: [ { binding: 0, - visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT, + visibility, buffer: { type }, }, ], }) ); } - return this.commonBindGroupLayouts.get(type)!; + return this.commonBindGroupLayouts.get(id)!; } - getBindGroupLayouts(indices: BindGroupIndices): GPUBindGroupLayout[] { + getVisibilityForEncoderType(encoderType: EncoderType) { + return encoderType === 'compute pass' ? GPUShaderStage.COMPUTE : GPUShaderStage.FRAGMENT; + } + + getBindGroupLayouts( + indices: BindGroupIndices, + type: GPUBufferBindingType, + encoderType: EncoderType + ): GPUBindGroupLayout[] { const bindGroupLayouts: GPUBindGroupLayout[] = []; - bindGroupLayouts[indices.a] = this.getBindGroupLayout('read-only-storage'); - bindGroupLayouts[indices.b] = this.getBindGroupLayout('read-only-storage'); - bindGroupLayouts[indices.out] = this.getBindGroupLayout('storage'); + const inputType = type === 'storage' ? 'read-only-storage' : 'uniform'; + const visibility = this.getVisibilityForEncoderType(encoderType); + bindGroupLayouts[indices.a] = this.getBindGroupLayout(inputType, visibility); + bindGroupLayouts[indices.b] = this.getBindGroupLayout(inputType, visibility); + if (type === 'storage' || encoderType === 'compute pass') { + bindGroupLayouts[indices.out] = this.getBindGroupLayout('storage', visibility); + } return bindGroupLayouts; } - createBindGroup(buffer: GPUBuffer, type: GPUBufferBindingType): GPUBindGroup { + createBindGroup( + buffer: GPUBuffer, + type: GPUBufferBindingType, + encoderType: EncoderType + ): GPUBindGroup { + const visibility = this.getVisibilityForEncoderType(encoderType); return this.device.createBindGroup({ - layout: this.getBindGroupLayout(type), + layout: this.getBindGroupLayout(type, visibility), entries: [{ binding: 0, resource: { buffer } }], }); } @@ -57,6 +100,7 @@ export class ProgrammableStateTest extends GPUTest { createBindingStatePipeline( encoderType: T, groups: BindGroupIndices, + type: GPUBufferBindingType, algorithm: string = 'a.value - b.value' ): GPUComputePipeline | GPURenderPipeline { switch (encoderType) { @@ -65,8 +109,8 @@ export class ProgrammableStateTest extends GPUTest { value : i32 }; - @group(${groups.a}) @binding(0) var a : Data; - @group(${groups.b}) @binding(0) var b : Data; + @group(${groups.a}) @binding(0) var<${type}> a : Data; + @group(${groups.b}) @binding(0) var<${type}> b : Data; @group(${groups.out}) @binding(0) var out : Data; @compute @workgroup_size(1) fn main() { @@ -77,7 +121,7 @@ export class ProgrammableStateTest extends GPUTest { return this.device.createComputePipeline({ layout: this.device.createPipelineLayout({ - bindGroupLayouts: this.getBindGroupLayouts(groups), + bindGroupLayouts: this.getBindGroupLayouts(groups, type, encoderType), }), compute: { module: this.device.createShaderModule({ @@ -92,7 +136,7 @@ export class ProgrammableStateTest extends GPUTest { const wgslShaders = { vertex: ` @vertex fn vert_main() -> @builtin(position) vec4 { - return vec4(0.5, 0.5, 0.0, 1.0); + return vec4(0, 0, 0, 1); } `, @@ -101,20 +145,23 @@ export class ProgrammableStateTest extends GPUTest { value : i32 }; - @group(${groups.a}) @binding(0) var a : Data; - @group(${groups.b}) @binding(0) var b : Data; + @group(${groups.a}) @binding(0) var<${type}> a : Data; + @group(${groups.b}) @binding(0) var<${type}> b : Data; @group(${groups.out}) @binding(0) var out : Data; - @fragment fn frag_main() -> @location(0) vec4 { + @fragment fn frag_main_storage() -> @location(0) vec4 { out.value = ${algorithm}; - return vec4(1.0, 0.0, 0.0, 1.0); + return vec4(1, 0, 0, 1); + } + @fragment fn frag_main_uniform() -> @location(0) vec4 { + return vec4(${algorithm}); } `, }; return this.device.createRenderPipeline({ layout: this.device.createPipelineLayout({ - bindGroupLayouts: this.getBindGroupLayouts(groups), + bindGroupLayouts: this.getBindGroupLayouts(groups, type, encoderType), }), vertex: { module: this.device.createShaderModule({ @@ -126,8 +173,8 @@ export class ProgrammableStateTest extends GPUTest { module: this.device.createShaderModule({ code: wgslShaders.fragment, }), - entryPoint: 'frag_main', - targets: [{ format: 'rgba8unorm' }], + entryPoint: type === 'uniform' ? 'frag_main_uniform' : 'frag_main_storage', + targets: [{ format: 'r32sint' }], }, primitive: { topology: 'point-list' }, }); @@ -137,6 +184,57 @@ export class ProgrammableStateTest extends GPUTest { } } + createEncoderForStateTest( + type: GPUBufferBindingType, + out: GPUBuffer, + ...params: Parameters + ): { + encoder: CreateEncoderType; + validateFinishAndSubmit: (shouldBeValid: boolean, submitShouldSucceedIfValid: boolean) => void; + } { + const encoderType = params[0]; + const renderTarget = this.createTextureTracked({ + size: [1, 1], + format: 'r32sint', + usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, + }); + + // Note: This nightmare of gibberish is trying the result of 2 hours of + // trying to get typescript to accept the code. Originally the code was + // effectively just + // + // const { encoder, validateFinishAndSubmit } = this.createEncoder(...); + // const fn = (b0, b1) => { validateFinishAndSubmit(b1, b1); if (...) { ... copyT2B ... } } + // return { encoder: e__, validateFinishAndSubmit: fn }; + // + // But TS didn't like it. I couldn't figure out why. + const encoderAndFinish = this.createEncoder(encoderType, { + attachmentInfo: { colorFormats: ['r32sint'] }, + targets: [renderTarget.createView()], + }); + + const validateFinishAndSubmit = ( + shouldBeValid: boolean, + submitShouldSucceedIfValid: boolean + ) => { + encoderAndFinish.validateFinishAndSubmit(shouldBeValid, submitShouldSucceedIfValid); + + if ( + type === 'uniform' && + (encoderType === 'render pass' || encoderType === 'render bundle') + ) { + const encoder = this.device.createCommandEncoder(); + encoder.copyTextureToBuffer({ texture: renderTarget }, { buffer: out }, [1, 1]); + this.device.queue.submit([encoder.finish()]); + } + }; + + return { + encoder: encoderAndFinish.encoder as CreateEncoderType, + validateFinishAndSubmit, + }; + } + setPipeline(pass: GPUBindingCommandsMixin, pipeline: GPUComputePipeline | GPURenderPipeline) { if (pass instanceof GPUComputePassEncoder) { pass.setPipeline(pipeline as GPUComputePipeline); diff --git a/src/webgpu/api/operation/command_buffer/programmable/state_tracking.spec.ts b/src/webgpu/api/operation/command_buffer/programmable/state_tracking.spec.ts index fe8ef3d4374f..3dd8b9f5392f 100644 --- a/src/webgpu/api/operation/command_buffer/programmable/state_tracking.spec.ts +++ b/src/webgpu/api/operation/command_buffer/programmable/state_tracking.spec.ts @@ -5,13 +5,18 @@ times in different orders) for setBindGroup and setPipeline. import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUConst } from '../../../../constants.js'; +import { MaxLimitsTestMixin } from '../../../../gpu_test.js'; import { kProgrammableEncoderTypes } from '../../../../util/command_buffer_maker.js'; import { ProgrammableStateTest } from './programmable_state_test.js'; -export const g = makeTestGroup(ProgrammableStateTest); +export const g = makeTestGroup(MaxLimitsTestMixin(ProgrammableStateTest)); -const kBufferUsage = GPUConst.BufferUsage.COPY_SRC | GPUConst.BufferUsage.STORAGE; +const kBufferUsage = + GPUConst.BufferUsage.COPY_SRC | + GPUConst.BufferUsage.COPY_DST | + GPUConst.BufferUsage.STORAGE | + GPUConst.BufferUsage.UNIFORM; g.test('bind_group_indices') .desc( @@ -24,6 +29,7 @@ g.test('bind_group_indices') u // .combine('encoderType', kProgrammableEncoderTypes) .beginSubcases() + .combine('type', ['storage', 'uniform'] as const) .combine('groupIndices', [ { a: 0, b: 1, out: 2 }, { a: 1, b: 2, out: 0 }, @@ -34,24 +40,40 @@ g.test('bind_group_indices') ]) ) .fn(t => { - const { encoderType, groupIndices } = t.params; + const { encoderType, groupIndices, type } = t.params; + t.skipIfNeedsStorageBuffersInFragmentStageAndHaveNone(type, encoderType); - const pipeline = t.createBindingStatePipeline(encoderType, groupIndices); + const pipeline = t.createBindingStatePipeline( + encoderType, + groupIndices, + type, + 'a.value - b.value' + ); + const inputType: GPUBufferBindingType = type === 'storage' ? 'read-only-storage' : 'uniform'; const out = t.makeBufferWithContents(new Int32Array([0]), kBufferUsage); const bindGroups = { a: t.createBindGroup( t.makeBufferWithContents(new Int32Array([3]), kBufferUsage), - 'read-only-storage' + inputType, + encoderType ), b: t.createBindGroup( t.makeBufferWithContents(new Int32Array([2]), kBufferUsage), - 'read-only-storage' + inputType, + encoderType ), - out: t.createBindGroup(out, 'storage'), + out: + encoderType === 'compute pass' || type === 'storage' + ? t.createBindGroup(out, 'storage', encoderType) + : null, }; - const { encoder, validateFinishAndSubmit } = t.createEncoder(encoderType); + const { encoder, validateFinishAndSubmit } = t.createEncoderForStateTest( + type, + out, + encoderType + ); t.setPipeline(encoder, pipeline); encoder.setBindGroup(groupIndices.a, bindGroups.a); @@ -73,6 +95,7 @@ g.test('bind_group_order') u // .combine('encoderType', kProgrammableEncoderTypes) .beginSubcases() + .combine('type', ['storage', 'uniform'] as const) .combine('setOrder', [ ['a', 'b', 'out'], ['b', 'out', 'a'], @@ -83,25 +106,41 @@ g.test('bind_group_order') ] as const) ) .fn(t => { - const { encoderType, setOrder } = t.params; + const { encoderType, setOrder, type } = t.params; + t.skipIfNeedsStorageBuffersInFragmentStageAndHaveNone(type, encoderType); const groupIndices = { a: 0, b: 1, out: 2 }; - const pipeline = t.createBindingStatePipeline(encoderType, groupIndices); + const pipeline = t.createBindingStatePipeline( + encoderType, + groupIndices, + type, + 'a.value - b.value' + ); const out = t.makeBufferWithContents(new Int32Array([0]), kBufferUsage); + const inputType: GPUBufferBindingType = type === 'storage' ? 'read-only-storage' : 'uniform'; const bindGroups = { a: t.createBindGroup( t.makeBufferWithContents(new Int32Array([3]), kBufferUsage), - 'read-only-storage' + inputType, + encoderType ), b: t.createBindGroup( t.makeBufferWithContents(new Int32Array([2]), kBufferUsage), - 'read-only-storage' + inputType, + encoderType ), - out: t.createBindGroup(out, 'storage'), + out: + encoderType === 'compute pass' || type === 'storage' + ? t.createBindGroup(out, 'storage', encoderType) + : null, }; - const { encoder, validateFinishAndSubmit } = t.createEncoder(encoderType); + const { encoder, validateFinishAndSubmit } = t.createEncoderForStateTest( + type, + out, + encoderType + ); t.setPipeline(encoder, pipeline); for (const bindingName of setOrder) { @@ -124,6 +163,7 @@ g.test('bind_group_before_pipeline') u // .combine('encoderType', kProgrammableEncoderTypes) .beginSubcases() + .combine('type', ['storage', 'uniform'] as const) .combineWithParams([ { setBefore: ['a', 'b'], setAfter: ['out'] }, { setBefore: ['a'], setAfter: ['b', 'out'] }, @@ -132,24 +172,41 @@ g.test('bind_group_before_pipeline') ] as const) ) .fn(t => { - const { encoderType, setBefore, setAfter } = t.params; + const { encoderType, type, setBefore, setAfter } = t.params; + t.skipIfNeedsStorageBuffersInFragmentStageAndHaveNone(type, encoderType); + const groupIndices = { a: 0, b: 1, out: 2 }; - const pipeline = t.createBindingStatePipeline(encoderType, groupIndices); + const pipeline = t.createBindingStatePipeline( + encoderType, + groupIndices, + type, + 'a.value - b.value' + ); const out = t.makeBufferWithContents(new Int32Array([0]), kBufferUsage); + const inputType: GPUBufferBindingType = type === 'storage' ? 'read-only-storage' : 'uniform'; const bindGroups = { a: t.createBindGroup( t.makeBufferWithContents(new Int32Array([3]), kBufferUsage), - 'read-only-storage' + inputType, + encoderType ), b: t.createBindGroup( t.makeBufferWithContents(new Int32Array([2]), kBufferUsage), - 'read-only-storage' + inputType, + encoderType ), - out: t.createBindGroup(out, 'storage'), + out: + encoderType === 'compute pass' || type === 'storage' + ? t.createBindGroup(out, 'storage', encoderType) + : null, }; - const { encoder, validateFinishAndSubmit } = t.createEncoder(encoderType); + const { encoder, validateFinishAndSubmit } = t.createEncoderForStateTest( + type, + out, + encoderType + ); for (const bindingName of setBefore) { encoder.setBindGroup(groupIndices[bindingName], bindGroups[bindingName]); @@ -176,21 +233,39 @@ g.test('one_bind_group_multiple_slots') .params(u => u // .combine('encoderType', kProgrammableEncoderTypes) + .beginSubcases() + .combine('type', ['storage', 'uniform'] as const) ) .fn(t => { - const { encoderType } = t.params; - const pipeline = t.createBindingStatePipeline(encoderType, { a: 0, b: 1, out: 2 }); + const { encoderType, type } = t.params; + t.skipIfNeedsStorageBuffersInFragmentStageAndHaveNone(type, encoderType); + + const pipeline = t.createBindingStatePipeline( + encoderType, + { a: 0, b: 1, out: 2 }, + type, + 'a.value - b.value' + ); const out = t.makeBufferWithContents(new Int32Array([1]), kBufferUsage); + const inputType: GPUBufferBindingType = type === 'storage' ? 'read-only-storage' : 'uniform'; const bindGroups = { ab: t.createBindGroup( t.makeBufferWithContents(new Int32Array([3]), kBufferUsage), - 'read-only-storage' + inputType, + encoderType ), - out: t.createBindGroup(out, 'storage'), + out: + encoderType === 'compute pass' || type === 'storage' + ? t.createBindGroup(out, 'storage', encoderType) + : null, }; - const { encoder, validateFinishAndSubmit } = t.createEncoder(encoderType); + const { encoder, validateFinishAndSubmit } = t.createEncoderForStateTest( + type, + out, + encoderType + ); t.setPipeline(encoder, pipeline); encoder.setBindGroup(0, bindGroups.ab); @@ -212,31 +287,54 @@ g.test('bind_group_multiple_sets') .params(u => u // .combine('encoderType', kProgrammableEncoderTypes) + .beginSubcases() + .combine('type', ['storage', 'uniform'] as const) ) .fn(t => { - const { encoderType } = t.params; - const pipeline = t.createBindingStatePipeline(encoderType, { a: 0, b: 1, out: 2 }); + const { encoderType, type } = t.params; + t.skipIfNeedsStorageBuffersInFragmentStageAndHaveNone(type, encoderType); + + const pipeline = t.createBindingStatePipeline( + encoderType, + { a: 0, b: 1, out: 2 }, + type, + 'a.value - b.value' + ); const badOut = t.makeBufferWithContents(new Int32Array([-1]), kBufferUsage); const out = t.makeBufferWithContents(new Int32Array([0]), kBufferUsage); + const inputType: GPUBufferBindingType = type === 'storage' ? 'read-only-storage' : 'uniform'; const bindGroups = { a: t.createBindGroup( t.makeBufferWithContents(new Int32Array([3]), kBufferUsage), - 'read-only-storage' + inputType, + encoderType ), b: t.createBindGroup( t.makeBufferWithContents(new Int32Array([2]), kBufferUsage), - 'read-only-storage' + inputType, + encoderType ), c: t.createBindGroup( t.makeBufferWithContents(new Int32Array([5]), kBufferUsage), - 'read-only-storage' + inputType, + encoderType ), - badOut: t.createBindGroup(badOut, 'storage'), - out: t.createBindGroup(out, 'storage'), + badOut: + encoderType === 'compute pass' || type === 'storage' + ? t.createBindGroup(badOut, 'storage', encoderType) + : null, + out: + encoderType === 'compute pass' || type === 'storage' + ? t.createBindGroup(out, 'storage', encoderType) + : null, }; - const { encoder, validateFinishAndSubmit } = t.createEncoder(encoderType); + const { encoder, validateFinishAndSubmit } = t.createEncoderForStateTest( + type, + out, + encoderType + ); encoder.setBindGroup(1, bindGroups.c); @@ -265,10 +363,18 @@ g.test('compatible_pipelines') ) .fn(t => { const { encoderType } = t.params; - const pipelineA = t.createBindingStatePipeline(encoderType, { a: 0, b: 1, out: 2 }); + t.skipIfNeedsStorageBuffersInFragmentStageAndHaveNone('storage', encoderType); + + const pipelineA = t.createBindingStatePipeline( + encoderType, + { a: 0, b: 1, out: 2 }, + 'storage', + 'a.value - b.value' + ); const pipelineB = t.createBindingStatePipeline( encoderType, { a: 0, b: 1, out: 2 }, + 'storage', 'a.value + b.value' ); @@ -277,17 +383,21 @@ g.test('compatible_pipelines') const bindGroups = { a: t.createBindGroup( t.makeBufferWithContents(new Int32Array([3]), kBufferUsage), - 'read-only-storage' + 'read-only-storage', + encoderType ), b: t.createBindGroup( t.makeBufferWithContents(new Int32Array([2]), kBufferUsage), - 'read-only-storage' + 'read-only-storage', + encoderType ), - outA: t.createBindGroup(outA, 'storage'), - outB: t.createBindGroup(outB, 'storage'), + outA: t.createBindGroup(outA, 'storage', encoderType), + outB: t.createBindGroup(outB, 'storage', encoderType), }; - const { encoder, validateFinishAndSubmit } = t.createEncoder(encoderType); + const { encoder, validateFinishAndSubmit } = t.createEncoder(encoderType, { + attachmentInfo: { colorFormats: ['r32sint'] }, + }); encoder.setBindGroup(0, bindGroups.a); encoder.setBindGroup(1, bindGroups.b); diff --git a/src/webgpu/api/validation/capability_checks/limits/limit_utils.ts b/src/webgpu/api/validation/capability_checks/limits/limit_utils.ts index 8ab31f04b9d7..3f72b90901e3 100644 --- a/src/webgpu/api/validation/capability_checks/limits/limit_utils.ts +++ b/src/webgpu/api/validation/capability_checks/limits/limit_utils.ts @@ -417,10 +417,12 @@ export class LimitTestsImpl extends GPUTestBase { if (extraLimits) { for (const [extraLimitStr, limitMode] of Object.entries(extraLimits)) { const extraLimit = extraLimitStr as GPUSupportedLimit; - requiredLimits[extraLimit] = - limitMode === 'defaultLimit' - ? getDefaultLimitForAdapter(adapter, extraLimit) - : (adapter.limits[extraLimit] as number); + if (adapter.limits[extraLimit] !== undefined) { + requiredLimits[extraLimit] = + limitMode === 'defaultLimit' + ? getDefaultLimitForAdapter(adapter, extraLimit) + : (adapter.limits[extraLimit] as number); + } } } diff --git a/src/webgpu/gpu_test.ts b/src/webgpu/gpu_test.ts index 1e7fac4a984e..9c63f5d15d2c 100644 --- a/src/webgpu/gpu_test.ts +++ b/src/webgpu/gpu_test.ts @@ -1131,9 +1131,11 @@ export class GPUTestBase extends Fixture { { attachmentInfo, occlusionQuerySet, + targets, }: { attachmentInfo?: GPURenderBundleEncoderDescriptor; occlusionQuerySet?: GPUQuerySet; + targets?: GPUTextureView[]; } = {} ): CommandBufferMaker { const fullAttachmentInfo = { @@ -1155,7 +1157,7 @@ export class GPUTestBase extends Fixture { case 'render bundle': { const device = this.device; const rbEncoder = device.createRenderBundleEncoder(fullAttachmentInfo); - const pass = this.createEncoder('render pass', { attachmentInfo }); + const pass = this.createEncoder('render pass', { attachmentInfo, targets }); return new CommandBufferMaker(this, rbEncoder, () => { pass.encoder.executeBundles([rbEncoder.finish()]); @@ -1205,10 +1207,10 @@ export class GPUTestBase extends Fixture { } } const passDesc: GPURenderPassDescriptor = { - colorAttachments: Array.from(fullAttachmentInfo.colorFormats, format => + colorAttachments: Array.from(fullAttachmentInfo.colorFormats, (format, i) => format ? { - view: makeAttachmentView(format), + view: targets ? targets[i] : makeAttachmentView(format), clearValue: [0, 0, 0, 0], loadOp: 'clear', storeOp: 'store', diff --git a/src/webgpu/print_environment.spec.ts b/src/webgpu/print_environment.spec.ts index f3ca67d3a2c0..9a47f8320cda 100644 --- a/src/webgpu/print_environment.spec.ts +++ b/src/webgpu/print_environment.spec.ts @@ -24,9 +24,11 @@ function consoleLogIfNotWPT(x: unknown) { g.test('info') .desc( - `Test which prints what global scope (e.g. worker type) it's running in. -Typically, tests will check for the presence of the feature they need (like HTMLCanvasElement) -and skip if it's not available. + `Test which prints what global scope (e.g. worker type) it's running in, and info about +the adapter and device that it gets. + +Note, other tests should not check the global scope type to detect features; instead, they should +check for the presence of the feature they need (like HTMLCanvasElement) and skip if not available. Run this test under various configurations to see different results (Window, worker scopes, Node, etc.) @@ -36,8 +38,19 @@ in the logs. On non-WPT runtimes, it will also print to the console with console WPT disallows console.log and doesn't support logs on passing tests, so this does nothing on WPT.` ) .fn(t => { - const isCompatibilityMode = (t.adapter as unknown as { isCompatibilityMode?: boolean }) - .isCompatibilityMode; + // `t.device` will be the default device, because no additional capabilities were requested. + const defaultDeviceProperties = Object.fromEntries( + (function* () { + const device = t.device as unknown as Record; + for (const key in device) { + // Skip things that we don't want to JSON.stringify. + if (['lost', 'queue', 'onuncapturederror', 'label'].includes(key)) { + continue; + } + yield [key, device[key]]; + } + })() + ); const info = JSON.stringify( { @@ -46,20 +59,20 @@ WPT disallows console.log and doesn't support logs on passing tests, so this doe globalTestConfig, baseResourcePath: getResourcePath(''), defaultRequestAdapterOptions: getDefaultRequestAdapterOptions(), - adapter: { - isFallbackAdapter: t.adapter.isFallbackAdapter, - isCompatibilityMode, - info: t.adapter.info, - features: Array.from(t.adapter.features), - limits: t.adapter.limits, - }, + // Print all of the properties of the adapter and defaultDeviceProperties. JSON.stringify + // will skip methods (e.g. adapter.requestDevice), because they're not stringifiable. + adapter: t.adapter, + defaultDevice: defaultDeviceProperties, }, - // Flatten objects with prototype chains into plain objects, using `for..in`. (Otherwise, - // properties from the prototype chain will be ignored and things will print as `{}`.) + // - Replace `undefined` with `null`. + // - Expand iterable things into arrays. + // - Flatten objects with prototype chains into plain objects, using `for..in`. (Otherwise, + // properties from the prototype chain will be ignored and things will print as `{}`.) (_key, value) => { if (value === undefined || value === null) return null; if (typeof value !== 'object') return value; if (value instanceof Array) return value; + if (Symbol.iterator in value) return Array.from(value as Iterable); const valueObj = value as Record; return Object.fromEntries(