-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
wgsl: Add compound statement tests (#3337)
Validation: - Check parsing of compound statements - Update break-if statement to add a case for a plain compound statement surrounding a break-if. - For a declaration in a compound statement, check potential uses and potentially conflicting declarations. Execution: Add execution tests for compound statement. Observe a value at various points relative to its declaration inside a compound statement. Add timings for new tests Fixed: #1634
- Loading branch information
Showing
5 changed files
with
295 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
export const description = ` | ||
Compound statement execution. | ||
`; | ||
|
||
import { makeTestGroup } from '../../../../common/framework/test_group.js'; | ||
import { keysOf } from '../../../../common/util/data_tables.js'; | ||
import { TypedArrayBufferView } from '../../../../common/util/util.js'; | ||
import { GPUTest } from '../../../gpu_test.js'; | ||
|
||
export const g = makeTestGroup(GPUTest); | ||
|
||
/** | ||
* Builds, runs then checks the output of a statement shader test. | ||
* | ||
* @param t The test object | ||
* @param ty The WGSL scalar type to be written | ||
* @param values The expected output values of type ty | ||
* @param wgsl_main The body of the WGSL entry point. | ||
*/ | ||
export function runStatementTest( | ||
t: GPUTest, | ||
ty: string, | ||
values: TypedArrayBufferView, | ||
wgsl_main: string | ||
) { | ||
const wgsl = ` | ||
struct Outputs { | ||
data : array<${ty}>, | ||
}; | ||
var<private> count: u32 = 0; | ||
@group(0) @binding(1) var<storage, read_write> outputs : Outputs; | ||
fn put(value : ${ty}) { | ||
outputs.data[count] = value; | ||
count += 1; | ||
} | ||
@compute @workgroup_size(1) | ||
fn main() { | ||
_ = &outputs; | ||
${wgsl_main} | ||
} | ||
`; | ||
|
||
const pipeline = t.device.createComputePipeline({ | ||
layout: 'auto', | ||
compute: { | ||
module: t.device.createShaderModule({ code: wgsl }), | ||
entryPoint: 'main', | ||
}, | ||
}); | ||
|
||
const maxOutputValues = 1000; | ||
const outputBuffer = t.device.createBuffer({ | ||
size: 4 * (1 + maxOutputValues), | ||
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC, | ||
}); | ||
|
||
const bindGroup = t.device.createBindGroup({ | ||
layout: pipeline.getBindGroupLayout(0), | ||
entries: [{ binding: 1, resource: { buffer: outputBuffer } }], | ||
}); | ||
|
||
// Run the shader. | ||
const encoder = t.device.createCommandEncoder(); | ||
const pass = encoder.beginComputePass(); | ||
pass.setPipeline(pipeline); | ||
pass.setBindGroup(0, bindGroup); | ||
pass.dispatchWorkgroups(1); | ||
pass.end(); | ||
t.queue.submit([encoder.finish()]); | ||
|
||
t.expectGPUBufferValuesEqual(outputBuffer, values); | ||
} | ||
|
||
// Consider a declaration X of identifier 'x' inside a compound statement. | ||
// Check the value of 'x' at various places relative to X: | ||
// a { b; X=c; d; { e; } } f; | ||
|
||
const kTests = { | ||
uses: { | ||
// Observe values without conflicting declarations. | ||
src: `let x = 1; | ||
put(x); | ||
{ | ||
put(x); | ||
let x = x+1; // The declaration in question | ||
put(x); | ||
{ | ||
put(x); | ||
} | ||
put(x); | ||
} | ||
put(x);`, | ||
values: [1, 1, 2, 2, 2, 1], | ||
}, | ||
shadowed: { | ||
// Observe values when shadowed | ||
src: `let x = 1; | ||
put(x); | ||
{ | ||
put(x); | ||
let x = x+1; // The declaration in question | ||
put(x); | ||
{ | ||
let x = x+1; // A shadow | ||
put(x); | ||
} | ||
put(x); | ||
} | ||
put(x);`, | ||
values: [1, 1, 2, 3, 2, 1], | ||
}, | ||
gone: { | ||
// The declaration goes out of scope. | ||
src: `{ | ||
let x = 2; // The declaration in question | ||
put(x); | ||
} | ||
let x = 1; | ||
put(x);`, | ||
values: [2, 1], | ||
}, | ||
} as const; | ||
|
||
g.test('decl') | ||
.desc('Tests the value of a declared value in a compound statment.') | ||
.params(u => u.combine('case', keysOf(kTests))) | ||
.fn(t => { | ||
runStatementTest( | ||
t, | ||
'i32', | ||
new Int32Array(kTests[t.params.case].values), | ||
kTests[t.params.case].src | ||
); | ||
}); |
98 changes: 98 additions & 0 deletions
98
src/webgpu/shader/validation/decl/compound_statement.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
export const description = ` | ||
Validation tests for declarations in compound statements. | ||
`; | ||
|
||
import { makeTestGroup } from '../../../../common/framework/test_group.js'; | ||
import { keysOf } from '../../../../common/util/data_tables.js'; | ||
import { ShaderValidationTest } from '../shader_validation_test.js'; | ||
|
||
export const g = makeTestGroup(ShaderValidationTest); | ||
|
||
// 9.1 Compound Statements | ||
// When a declaration is one of those statements, its identifier is in scope from | ||
// the start of the next statement until the end of the compound statement. | ||
// | ||
// Enumerating cases: Consider a declaration X inside a compound statement. | ||
// The X declaration should be tested with potential uses and potentially | ||
// conflicting declarations in positions [a, b, c, d, e], in the following: | ||
// a { b; X; c; { d; } } e; | ||
|
||
const kConflictTests = { | ||
a: { | ||
src: 'let x = 1; { let x = 1; }', | ||
pass: true, | ||
}, | ||
bc: { | ||
src: '{let x = 1; let x = 1; }', | ||
pass: false, | ||
}, | ||
d: { | ||
src: '{let x = 1; { let x = 1; }}', | ||
pass: true, | ||
}, | ||
e: { | ||
src: '{let x = 1; } let x = 1;', | ||
pass: true, | ||
}, | ||
}; | ||
|
||
g.test('decl_conflict') | ||
.desc( | ||
'Test a potentially conflicting declaration relative to a declaration in a compound statement' | ||
) | ||
.params(u => u.combine('case', keysOf(kConflictTests))) | ||
.fn(t => { | ||
const wgsl = ` | ||
@vertex fn vtx() -> @builtin(position) vec4f { | ||
${kConflictTests[t.params.case].src} | ||
return vec4f(1); | ||
}`; | ||
t.expectCompileResult(kConflictTests[t.params.case].pass, wgsl); | ||
}); | ||
|
||
const kUseTests = { | ||
a: { | ||
src: 'let y = x; { let x = 1; }', | ||
pass: false, // not visible | ||
}, | ||
b: { | ||
src: '{ let y = x; let x = 1; }', | ||
pass: false, // not visible | ||
}, | ||
self: { | ||
src: '{ let x = (x);}', | ||
pass: false, // not visible | ||
}, | ||
c_yes: { | ||
src: '{ const x = 1; const_assert x == 1; }', | ||
pass: true, | ||
}, | ||
c_no: { | ||
src: '{ const x = 1; const_assert x == 2; }', | ||
pass: false, | ||
}, | ||
d_yes: { | ||
src: '{ const x = 1; { const_assert x == 1; }}', | ||
pass: true, | ||
}, | ||
d_no: { | ||
src: '{ const x = 1; { const_assert x == 2; }}', | ||
pass: false, | ||
}, | ||
e: { | ||
src: '{ const x = 1; } let y = x;', | ||
pass: false, // not visible | ||
}, | ||
}; | ||
|
||
g.test('decl_use') | ||
.desc('Test a use of a declaration in a compound statement') | ||
.params(u => u.combine('case', keysOf(kUseTests))) | ||
.fn(t => { | ||
const wgsl = ` | ||
@vertex fn vtx() -> @builtin(position) vec4f { | ||
${kUseTests[t.params.case].src} | ||
return vec4f(1); | ||
}`; | ||
t.expectCompileResult(kUseTests[t.params.case].pass, wgsl); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
export const description = `Validation tests for compound statements`; | ||
|
||
import { makeTestGroup } from '../../../../common/framework/test_group.js'; | ||
import { keysOf } from '../../../../common/util/data_tables.js'; | ||
import { ShaderValidationTest } from '../shader_validation_test.js'; | ||
|
||
export const g = makeTestGroup(ShaderValidationTest); | ||
|
||
const kTests = { | ||
missing_start: { | ||
src: '}', | ||
pass: false, | ||
}, | ||
missing_end: { | ||
src: '{', | ||
pass: false, | ||
}, | ||
empty: { | ||
src: '{}', | ||
pass: true, | ||
}, | ||
semicolon: { | ||
src: '{;}', | ||
pass: true, | ||
}, | ||
semicolons: { | ||
src: '{;;}', | ||
pass: true, | ||
}, | ||
decl: { | ||
src: '{const c = 1;}', | ||
pass: true, | ||
}, | ||
nested: { | ||
src: '{ {} }', | ||
pass: true, | ||
}, | ||
}; | ||
|
||
g.test('parse') | ||
.desc('Test that compound statments parse') | ||
.params(u => u.combine('stmt', keysOf(kTests))) | ||
.fn(t => { | ||
const code = ` | ||
@vertex | ||
fn vtx() -> @builtin(position) vec4f { | ||
${kTests[t.params.stmt].src} | ||
return vec4f(1); | ||
} | ||
`; | ||
t.expectCompileResult(kTests[t.params.stmt].pass, code); | ||
}); |