export const description = `
ShaderModule CompilationInfo tests.
`;
import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { assert } from '../../../../common/util/util.js';
import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
const kValidShaderSources = [
{
valid: true,
name: 'ascii',
_code: `
@vertex fn main() -> @builtin(position) vec4<f32> {
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
}`,
},
{
valid: true,
name: 'unicode',
_code: `
// ι ηΉγ·γ§γΌγγΌ π©βπ»
@vertex fn main() -> @builtin(position) vec4<f32> {
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
}`,
},
];
const kInvalidShaderSources = [
{
valid: false,
name: 'ascii',
_errorLine: 4,
_code: `
@vertex fn main() -> @builtin(position) vec4<f32> {
// Expected Error: unknown function 'unknown'
return unknown(0.0, 0.0, 0.0, 1.0);
}`,
},
{
valid: false,
name: 'unicode',
_errorLine: 5,
_code: `
// ι ηΉγ·γ§γΌγγΌ π©βπ»
@vertex fn main() -> @builtin(position) vec4<f32> {
// Expected Error: unknown function 'unknown'
return unknown(0.0, 0.0, 0.0, 1.0);
}`,
},
{
valid: false,
name: 'carriage-return',
_errorLine: 5,
_code:
`
@vertex fn main() -> @builtin(position) vec4<f32> {` +
'\r\n' +
`
// Expected Error: unknown function 'unknown'
return unknown(0.0, 0.0, 0.0, 1.0);
}`,
},
{
valid: false,
name: 'unicode-multi-byte-characters',
_errorLine: 1,
_errorLinePos: 19,
_code: `/*πππππππ*/?
// Expected Error: invalid character found`,
},
];
const kAllShaderSources = [...kValidShaderSources, ...kInvalidShaderSources];
g.test('getCompilationInfo_returns')
.desc(
`
Test that getCompilationInfo() can be called on any ShaderModule.
- Test for both valid and invalid shader modules.
- Test for shader modules containing only ASCII and those containing unicode characters.
- Test that the compilation info for valid shader modules contains no errors.
- Test that the compilation info for invalid shader modules contains at least one error.`
)
.params(u => u.combineWithParams(kAllShaderSources))
.fn(async t => {
const { _code, valid } = t.params;
const shaderModule = t.expectGPUError(
'validation',
() => {
return t.device.createShaderModule({ code: _code });
},
!valid
);
const info = await shaderModule.getCompilationInfo();
t.expect(
info instanceof GPUCompilationInfo,
'Expected a GPUCompilationInfo object to be returned'
);
let errorCount = 0;
for (const message of info.messages) {
if (message.type === 'error') {
errorCount++;
}
}
if (valid) {
t.expect(errorCount === 0, "Expected zero GPUCompilationMessages of type 'error'");
} else {
t.expect(errorCount > 0, "Expected at least one GPUCompilationMessages of type 'error'");
}
});
g.test('line_number_and_position')
.desc(
`
Test that line numbers reported by compilationInfo either point at an appropriate line and
position or at 0:0, indicating an unknown position.
- Test for invalid shader modules containing containing at least one error.
- Test for shader modules containing only ASCII and those containing unicode characters.`
)
.params(u => u.combineWithParams(kInvalidShaderSources))
.fn(async t => {
const { _code, _errorLine, _errorLinePos } = t.params;
const shaderModule = t.expectGPUError('validation', () => {
return t.device.createShaderModule({ code: _code });
});
const info = await shaderModule.getCompilationInfo();
let foundAppropriateError = false;
for (const message of info.messages) {
if (message.type === 'error') {
t.expect(
(message.lineNum === 0) === (message.linePos === 0),
`Got message.lineNum ${message.lineNum}, .linePos ${message.linePos}, but GPUCompilationMessage should specify both or neither`
);
if (message.lineNum === 0) {
foundAppropriateError = true;
break;
}
if (message.lineNum === _errorLine) {
foundAppropriateError = true;
if (_errorLinePos !== undefined) {
t.expect(
message.linePos === _errorLinePos,
`Got message.linePos ${message.linePos}, expected ${_errorLinePos}`
);
}
break;
}
}
}
t.expect(
foundAppropriateError,
'Expected to find an error which corresponded with the erroneous line'
);
});
g.test('offset_and_length')
.desc(
`Test that message offsets and lengths are valid and align with any reported lineNum and linePos.
- Test for valid and invalid shader modules.
- Test for shader modules containing only ASCII and those containing unicode characters.`
)
.params(u => u.combineWithParams(kAllShaderSources))
.fn(async t => {
const { _code, valid } = t.params;
const shaderModule = t.expectGPUError(
'validation',
() => {
return t.device.createShaderModule({ code: _code });
},
!valid
);
const info = await shaderModule.getCompilationInfo();
for (const message of info.messages) {
t.expect(
message.offset <= _code.length && message.offset + message.length <= _code.length,
'message.offset and .length should be within the shader source'
);
if (message.lineNum !== 0 && message.linePos !== 0) {
let lineOffset = 0;
for (let i = 0; i < message.lineNum - 1; ++i) {
lineOffset = _code.indexOf('\n', lineOffset);
assert(lineOffset !== -1);
lineOffset += 1;
}
const expectedOffset = lineOffset + message.linePos - 1;
t.expect(
message.offset === expectedOffset,
`message.lineNum (${message.lineNum}) and .linePos (${message.linePos}) point to a different offset (${lineOffset} + ${message.linePos} - 1 = ${expectedOffset}) than .offset (${message.offset})`
);
}
}
});