Bug 1962037 - test(webgpu): update CTS to c09e68cdaa4aded26b769443c743985a6cedd383 r=webgpu-reviewers,nical

Differential Revision: https://phabricator.services.mozilla.com/D246414
This commit is contained in:
Erich Gubler
2025-04-28 20:34:55 +00:00
parent 38bc73cdb8
commit 746586f2d6
399 changed files with 8192 additions and 5497 deletions

View File

@@ -258,8 +258,23 @@ digits of precision.
For the CTS it is often sufficient to calculate the true value using TypeScript, For the CTS it is often sufficient to calculate the true value using TypeScript,
since its native number format is higher precision (double-precision/f64), so since its native number format is higher precision (double-precision/f64), so
all f64, f32, and f16 values can be represented in it. Where this breaks down all f64, f32, and f16 values can be represented in it. Unfortunately, the
will be discussed in the section on compile time vs runtime execution. results of some operations cannot be exactly represent in double-precision. A
simple example here is subtracting a small magnitude number from a large
magnitude number.
Say we have `x - y` where `x = 1.0` and `y = 1.17e-38` (which is smallest
normal in f32)
In doing the subtraction, all the significant bits of `y` are lost. The result
in JS uses round-to-even, and we get `x - y = x` which is not the true value of
this operation
The CTS does best effort on these important edge cases to allow for all
acceptable results of these operations. Internally this boils down creating to
an interval bounding the true value. Where this breaks down will further be
discussed in the section on compile time vs runtime execution.
The true value is sometimes representable exactly as a floating point value, but The true value is sometimes representable exactly as a floating point value, but
often is not. often is not.
@@ -899,6 +914,7 @@ shader being run.
|------------------------|---------------:|------------:|---------:|--------------:|-----------------------------:| |------------------------|---------------:|------------:|---------:|--------------:|-----------------------------:|
| Negative Infinity | -∞ | 0xff80 0000 | 1 | 1111 1111 | 0000 0000 0000 0000 0000 000 | | Negative Infinity | -∞ | 0xff80 0000 | 1 | 1111 1111 | 0000 0000 0000 0000 0000 000 |
| Min Negative Normal | -3.40282346E38 | 0xff7f ffff | 1 | 1111 1110 | 1111 1111 1111 1111 1111 111 | | Min Negative Normal | -3.40282346E38 | 0xff7f ffff | 1 | 1111 1110 | 1111 1111 1111 1111 1111 111 |
| Max Negative i32 | -2147483648 | 0xCF00 0000 | 1 | 1001 1110 | 0000 0000 0000 0000 0000 000 |
| Max Negative Normal | -1.1754943E38 | 0x8080 0000 | 1 | 0000 0001 | 0000 0000 0000 0000 0000 000 | | Max Negative Normal | -1.1754943E38 | 0x8080 0000 | 1 | 0000 0001 | 0000 0000 0000 0000 0000 000 |
| Min Negative Subnormal | -1.1754942E-38 | 0x807f ffff | 1 | 0000 0000 | 1111 1111 1111 1111 1111 111 | | Min Negative Subnormal | -1.1754942E-38 | 0x807f ffff | 1 | 0000 0000 | 1111 1111 1111 1111 1111 111 |
| Max Negative Subnormal | -1.4012984E45 | 0x8000 0001 | 1 | 0000 0000 | 0000 0000 0000 0000 0000 001 | | Max Negative Subnormal | -1.4012984E45 | 0x8000 0001 | 1 | 0000 0000 | 0000 0000 0000 0000 0000 001 |
@@ -907,9 +923,12 @@ shader being run.
| Min Positive Subnormal | 1.4012984E45 | 0x0000 0001 | 0 | 0000 0000 | 0000 0000 0000 0000 0000 001 | | Min Positive Subnormal | 1.4012984E45 | 0x0000 0001 | 0 | 0000 0000 | 0000 0000 0000 0000 0000 001 |
| Max Positive Subnormal | 1.1754942E-38 | 0x007f ffff | 0 | 0000 0000 | 1111 1111 1111 1111 1111 111 | | Max Positive Subnormal | 1.1754942E-38 | 0x007f ffff | 0 | 0000 0000 | 1111 1111 1111 1111 1111 111 |
| Min Positive Normal | 1.1754943E38 | 0x0080 0000 | 0 | 0000 0001 | 0000 0000 0000 0000 0000 000 | | Min Positive Normal | 1.1754943E38 | 0x0080 0000 | 0 | 0000 0001 | 0000 0000 0000 0000 0000 000 |
| Max Positive i32 | 2147483520 | 0x4efff fff | 0 | 1001 1101 | 1111 1111 1111 1111 1111 111 |
| Max Positive u32 | 4294967040 | 0x4f7f ffff | 0 | 1001 1110 | 1111 1111 1111 1111 1111 111 |
| Max Positive Normal | 3.40282346E38 | 0x7f7f ffff | 0 | 1111 1110 | 1111 1111 1111 1111 1111 111 | | Max Positive Normal | 3.40282346E38 | 0x7f7f ffff | 0 | 1111 1110 | 1111 1111 1111 1111 1111 111 |
| Negative Infinity | ∞ | 0x7f80 0000 | 0 | 1111 1111 | 0000 0000 0000 0000 0000 000 | | Negative Infinity | ∞ | 0x7f80 0000 | 0 | 1111 1111 | 0000 0000 0000 0000 0000 000 |
### Significant f16 Values ### Significant f16 Values
| Name | Decimal (~) | Hex | Sign Bit | Exponent Bits | Significand Bits | | Name | Decimal (~) | Hex | Sign Bit | Exponent Bits | Significand Bits |

View File

@@ -250,7 +250,7 @@ export class Fixture<S extends SubcaseBatchState = SubcaseBatchState> {
* Wraps an async function, passing it an `Error` object recording the original stack trace. * Wraps an async function, passing it an `Error` object recording the original stack trace.
* The async work will be implicitly waited upon before reporting a test status. * The async work will be implicitly waited upon before reporting a test status.
*/ */
protected eventualAsyncExpectation<T>(fn: (niceStack: Error) => Promise<T>): void { eventualAsyncExpectation<T>(fn: (niceStack: Error) => Promise<T>): void {
const promise = fn(new Error()); const promise = fn(new Error());
this.eventualExpectations.push(promise); this.eventualExpectations.push(promise);
} }

View File

@@ -23,8 +23,7 @@ function unregisterAllServiceWorkers() {
// important, so we try our best (and don't worry about shutdown performance or disabling bfcache). // important, so we try our best (and don't worry about shutdown performance or disabling bfcache).
// (We could try 'visibilitychange', but since it can happen in the middle of the page lifetime, // (We could try 'visibilitychange', but since it can happen in the middle of the page lifetime,
// it is more likely to have unintended consequences and would need to do different stuff.) // it is more likely to have unintended consequences and would need to do different stuff.)
// - 'unload' supposedly always disables the bfcache. // - 'unload' supposedly always disables the bfcache, but is deprecated in Chrome.
window.addEventListener('unload', runShutdownTasks);
// - 'beforeunload' may disable the bfcache but may be called more reliably than 'unload'. // - 'beforeunload' may disable the bfcache but may be called more reliably than 'unload'.
window.addEventListener('beforeunload', runShutdownTasks); window.addEventListener('beforeunload', runShutdownTasks);
// - 'pagehide' won't disable the bfcache but may be called more reliably than the others. // - 'pagehide' won't disable the bfcache but may be called more reliably than the others.

View File

@@ -197,23 +197,25 @@ export function getGPU(recorder: TestCaseRecorder | null): GPU {
if (defaultRequestAdapterOptions) { if (defaultRequestAdapterOptions) {
// eslint-disable-next-line @typescript-eslint/unbound-method // eslint-disable-next-line @typescript-eslint/unbound-method
const oldFn = impl.requestAdapter; const origRequestAdapterFn = impl.requestAdapter;
impl.requestAdapter = function (
options?: GPURequestAdapterOptions // eslint-disable-next-line @typescript-eslint/unbound-method
): Promise<GPUAdapter | null> { Object.defineProperty(impl, 'requestAdapter', {
const promise = oldFn.call(this, { ...defaultRequestAdapterOptions, ...options }); configurable: true,
if (recorder) { async value(options?: GPURequestAdapterOptions) {
void promise.then(adapter => { const adapter = await origRequestAdapterFn.call(this, {
if (adapter) { ...defaultRequestAdapterOptions,
...options,
});
if (recorder && adapter) {
const adapterInfo = adapter.info; const adapterInfo = adapter.info;
const infoString = `Adapter: ${adapterInfo.vendor} / ${adapterInfo.architecture} / ${adapterInfo.device}`; const infoString = `Adapter: ${adapterInfo.vendor} / ${adapterInfo.architecture} / ${adapterInfo.device}`;
recorder.debug(new ErrorWithExtra(infoString, () => ({ adapterInfo }))); recorder.debug(new ErrorWithExtra(infoString, () => ({ adapterInfo })));
} }
return adapter;
},
}); });
} }
return promise;
};
}
return impl; return impl;
} }

View File

@@ -1,112 +1,112 @@
{ {
"webgpu/shader/execution/binary/af_addition.bin": "8a6dae1a", "webgpu/shader/execution/binary/af_addition.bin": "50e6a567",
"webgpu/shader/execution/binary/af_logical.bin": "801f1d3", "webgpu/shader/execution/binary/af_logical.bin": "156f7a3e",
"webgpu/shader/execution/binary/af_division.bin": "542849b0", "webgpu/shader/execution/binary/af_division.bin": "5fb5aad5",
"webgpu/shader/execution/binary/af_matrix_addition.bin": "11e50be6", "webgpu/shader/execution/binary/af_matrix_addition.bin": "4a10b9bf",
"webgpu/shader/execution/binary/af_matrix_subtraction.bin": "ce90174f", "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "775955dd",
"webgpu/shader/execution/binary/af_multiplication.bin": "d1110a67", "webgpu/shader/execution/binary/af_multiplication.bin": "8f7cdc6c",
"webgpu/shader/execution/binary/af_remainder.bin": "85c8dbd0", "webgpu/shader/execution/binary/af_remainder.bin": "f13de72f",
"webgpu/shader/execution/binary/af_subtraction.bin": "a188d924", "webgpu/shader/execution/binary/af_subtraction.bin": "91cdd21e",
"webgpu/shader/execution/binary/f16_addition.bin": "1aa58ad8", "webgpu/shader/execution/binary/f16_addition.bin": "6854bf3d",
"webgpu/shader/execution/binary/f16_logical.bin": "4a1c8221", "webgpu/shader/execution/binary/f16_logical.bin": "8ff07c74",
"webgpu/shader/execution/binary/f16_division.bin": "189722c1", "webgpu/shader/execution/binary/f16_division.bin": "6ff84e12",
"webgpu/shader/execution/binary/f16_matrix_addition.bin": "d18b795d", "webgpu/shader/execution/binary/f16_matrix_addition.bin": "57f7896",
"webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "d1ca04cd", "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "a30cd925",
"webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "74e7f534", "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "7319df75",
"webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "725faf4a", "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "b1c05ecf",
"webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "970e74ea", "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "21b437ec",
"webgpu/shader/execution/binary/f16_multiplication.bin": "cc6b9ad1", "webgpu/shader/execution/binary/f16_multiplication.bin": "4638fb34",
"webgpu/shader/execution/binary/f16_remainder.bin": "ef5b649", "webgpu/shader/execution/binary/f16_remainder.bin": "44574387",
"webgpu/shader/execution/binary/f16_subtraction.bin": "7affdaf5", "webgpu/shader/execution/binary/f16_subtraction.bin": "820e75de",
"webgpu/shader/execution/binary/f32_addition.bin": "66cd04fa", "webgpu/shader/execution/binary/f32_addition.bin": "a4f72976",
"webgpu/shader/execution/binary/f32_logical.bin": "ccddd86", "webgpu/shader/execution/binary/f32_logical.bin": "535674fe",
"webgpu/shader/execution/binary/f32_division.bin": "39984166", "webgpu/shader/execution/binary/f32_division.bin": "4959d8cd",
"webgpu/shader/execution/binary/f32_matrix_addition.bin": "8a6375d5", "webgpu/shader/execution/binary/f32_matrix_addition.bin": "bb179d37",
"webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "7a972729", "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "503ab436",
"webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "67a9a7f8", "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "234e8380",
"webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "bdead4ae", "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "55b30efc",
"webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "61ba6fc7", "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "4e7e58bf",
"webgpu/shader/execution/binary/f32_multiplication.bin": "ce9a8e70", "webgpu/shader/execution/binary/f32_multiplication.bin": "6a2a2d91",
"webgpu/shader/execution/binary/f32_remainder.bin": "8e879118", "webgpu/shader/execution/binary/f32_remainder.bin": "f8e1d804",
"webgpu/shader/execution/binary/f32_subtraction.bin": "e54a0b53", "webgpu/shader/execution/binary/f32_subtraction.bin": "fce2ee14",
"webgpu/shader/execution/binary/i32_arithmetic.bin": "2796c7a1", "webgpu/shader/execution/binary/i32_arithmetic.bin": "9bfbc49b",
"webgpu/shader/execution/binary/i32_comparison.bin": "b6cccd16", "webgpu/shader/execution/binary/i32_comparison.bin": "537c83e1",
"webgpu/shader/execution/binary/u32_arithmetic.bin": "b6cd9a78", "webgpu/shader/execution/binary/u32_arithmetic.bin": "2f58bba2",
"webgpu/shader/execution/binary/u32_comparison.bin": "a79879", "webgpu/shader/execution/binary/u32_comparison.bin": "ba9e997d",
"webgpu/shader/execution/abs.bin": "f36c9714", "webgpu/shader/execution/abs.bin": "7d9e6b9c",
"webgpu/shader/execution/acos.bin": "5b2c76ce", "webgpu/shader/execution/acos.bin": "14388910",
"webgpu/shader/execution/acosh.bin": "2a75f9b8", "webgpu/shader/execution/acosh.bin": "94a4bdba",
"webgpu/shader/execution/asin.bin": "6c642f6f", "webgpu/shader/execution/asin.bin": "349b6e0e",
"webgpu/shader/execution/asinh.bin": "bbfe9056", "webgpu/shader/execution/asinh.bin": "28771ac3",
"webgpu/shader/execution/atan.bin": "9ce43da3", "webgpu/shader/execution/atan.bin": "1bc1d94d",
"webgpu/shader/execution/atan2.bin": "68fe0f2", "webgpu/shader/execution/atan2.bin": "38b37c44",
"webgpu/shader/execution/atanh.bin": "3963222", "webgpu/shader/execution/atanh.bin": "a5f7aee5",
"webgpu/shader/execution/bitcast.bin": "e3162a7e", "webgpu/shader/execution/bitcast.bin": "a8994ad4",
"webgpu/shader/execution/ceil.bin": "a676b1e", "webgpu/shader/execution/ceil.bin": "73f16d7b",
"webgpu/shader/execution/clamp.bin": "14701cf7", "webgpu/shader/execution/clamp.bin": "a690f522",
"webgpu/shader/execution/cos.bin": "1483b62b", "webgpu/shader/execution/cos.bin": "89be2f32",
"webgpu/shader/execution/cosh.bin": "ce7f0632", "webgpu/shader/execution/cosh.bin": "6a0f3e8b",
"webgpu/shader/execution/cross.bin": "f9a18bd5", "webgpu/shader/execution/cross.bin": "aa9d40a1",
"webgpu/shader/execution/degrees.bin": "98276d75", "webgpu/shader/execution/degrees.bin": "8026a5db",
"webgpu/shader/execution/determinant.bin": "4a956856", "webgpu/shader/execution/determinant.bin": "1694a349",
"webgpu/shader/execution/distance.bin": "22d0592a", "webgpu/shader/execution/distance.bin": "a7638a71",
"webgpu/shader/execution/dot.bin": "ed60c916", "webgpu/shader/execution/dot.bin": "f0ef226f",
"webgpu/shader/execution/exp.bin": "6d7b1fbf", "webgpu/shader/execution/exp.bin": "435e1646",
"webgpu/shader/execution/exp2.bin": "91899596", "webgpu/shader/execution/exp2.bin": "804c653e",
"webgpu/shader/execution/faceForward.bin": "44446c0b", "webgpu/shader/execution/faceForward.bin": "8c738be9",
"webgpu/shader/execution/floor.bin": "549c5f0d", "webgpu/shader/execution/floor.bin": "f6441e05",
"webgpu/shader/execution/fma.bin": "489c4998", "webgpu/shader/execution/fma.bin": "4ee13b1a",
"webgpu/shader/execution/fract.bin": "cb3959f9", "webgpu/shader/execution/fract.bin": "c65b7672",
"webgpu/shader/execution/frexp.bin": "2530b9b6", "webgpu/shader/execution/frexp.bin": "4ac71f4b",
"webgpu/shader/execution/inverseSqrt.bin": "4433898f", "webgpu/shader/execution/inverseSqrt.bin": "1cbcea5d",
"webgpu/shader/execution/ldexp.bin": "e37552e8", "webgpu/shader/execution/ldexp.bin": "b4e969fb",
"webgpu/shader/execution/length.bin": "3eeb0337", "webgpu/shader/execution/length.bin": "55a89c1e",
"webgpu/shader/execution/log.bin": "87c4c21", "webgpu/shader/execution/log.bin": "b06012a8",
"webgpu/shader/execution/log2.bin": "8f826e9f", "webgpu/shader/execution/log2.bin": "9417099a",
"webgpu/shader/execution/max.bin": "60e2b9d2", "webgpu/shader/execution/max.bin": "e7a5826",
"webgpu/shader/execution/min.bin": "943cd5ce", "webgpu/shader/execution/min.bin": "7ef323e1",
"webgpu/shader/execution/mix.bin": "9526816d", "webgpu/shader/execution/mix.bin": "6eb306f",
"webgpu/shader/execution/modf.bin": "1e25f8b3", "webgpu/shader/execution/modf.bin": "a9ad9cfc",
"webgpu/shader/execution/normalize.bin": "de04cde2", "webgpu/shader/execution/normalize.bin": "c15ea8",
"webgpu/shader/execution/pack2x16float.bin": "4479a7f", "webgpu/shader/execution/pack2x16float.bin": "f2cedced",
"webgpu/shader/execution/pow.bin": "c43650f6", "webgpu/shader/execution/pow.bin": "71979830",
"webgpu/shader/execution/quantizeToF16.bin": "eb0e400b", "webgpu/shader/execution/quantizeToF16.bin": "b6bfcd52",
"webgpu/shader/execution/radians.bin": "e5608719", "webgpu/shader/execution/radians.bin": "9e5a449a",
"webgpu/shader/execution/reflect.bin": "8913d349", "webgpu/shader/execution/reflect.bin": "dd2159f6",
"webgpu/shader/execution/refract.bin": "6ac45f2", "webgpu/shader/execution/refract.bin": "209a8278",
"webgpu/shader/execution/round.bin": "5bb21704", "webgpu/shader/execution/round.bin": "ffb75a5e",
"webgpu/shader/execution/saturate.bin": "8b7a0f64", "webgpu/shader/execution/saturate.bin": "97db14f4",
"webgpu/shader/execution/sign.bin": "22ced674", "webgpu/shader/execution/sign.bin": "34388f8e",
"webgpu/shader/execution/sin.bin": "7bd2d5a2", "webgpu/shader/execution/sin.bin": "96bf69b3",
"webgpu/shader/execution/sinh.bin": "6b09bc46", "webgpu/shader/execution/sinh.bin": "6602a539",
"webgpu/shader/execution/smoothstep.bin": "9caf5eb8", "webgpu/shader/execution/smoothstep.bin": "aed55251",
"webgpu/shader/execution/sqrt.bin": "515cfcf2", "webgpu/shader/execution/sqrt.bin": "35613b62",
"webgpu/shader/execution/step.bin": "a657a4e7", "webgpu/shader/execution/step.bin": "1349c866",
"webgpu/shader/execution/tan.bin": "b555744", "webgpu/shader/execution/tan.bin": "806d67e8",
"webgpu/shader/execution/tanh.bin": "3e16eb6d", "webgpu/shader/execution/tanh.bin": "2698b5d1",
"webgpu/shader/execution/transpose.bin": "80dabbe8", "webgpu/shader/execution/transpose.bin": "4ce90543",
"webgpu/shader/execution/trunc.bin": "3d4ef4d5", "webgpu/shader/execution/trunc.bin": "4bbb7aaf",
"webgpu/shader/execution/unpack2x16float.bin": "c8d18fb8", "webgpu/shader/execution/unpack2x16float.bin": "6b01b9d6",
"webgpu/shader/execution/unpack2x16snorm.bin": "7a14d340", "webgpu/shader/execution/unpack2x16snorm.bin": "e8c8c841",
"webgpu/shader/execution/unpack2x16unorm.bin": "16978649", "webgpu/shader/execution/unpack2x16unorm.bin": "4c869eb8",
"webgpu/shader/execution/unpack4x8snorm.bin": "9f9a1b81", "webgpu/shader/execution/unpack4x8snorm.bin": "794c9465",
"webgpu/shader/execution/unpack4x8unorm.bin": "c4ffba6b", "webgpu/shader/execution/unpack4x8unorm.bin": "26501fe4",
"webgpu/shader/execution/unary/af_arithmetic.bin": "4e816dcb", "webgpu/shader/execution/unary/af_arithmetic.bin": "7a7a4fdc",
"webgpu/shader/execution/unary/af_assignment.bin": "f1c510e5", "webgpu/shader/execution/unary/af_assignment.bin": "11a8b60c",
"webgpu/shader/execution/unary/bool_conversion.bin": "fc23c738", "webgpu/shader/execution/unary/bool_conversion.bin": "be5e9d2d",
"webgpu/shader/execution/unary/f16_arithmetic.bin": "502df71c", "webgpu/shader/execution/unary/f16_arithmetic.bin": "c98e7af3",
"webgpu/shader/execution/unary/f16_conversion.bin": "8ba3360a", "webgpu/shader/execution/unary/f16_conversion.bin": "931541aa",
"webgpu/shader/execution/unary/f32_arithmetic.bin": "90bd65ee", "webgpu/shader/execution/unary/f32_arithmetic.bin": "99619832",
"webgpu/shader/execution/unary/f32_conversion.bin": "54eb496a", "webgpu/shader/execution/unary/f32_conversion.bin": "9a872074",
"webgpu/shader/execution/unary/i32_arithmetic.bin": "bc9bcacd", "webgpu/shader/execution/unary/i32_arithmetic.bin": "e68d3b9d",
"webgpu/shader/execution/unary/i32_conversion.bin": "1caf76fc", "webgpu/shader/execution/unary/i32_conversion.bin": "a09e6602",
"webgpu/shader/execution/unary/u32_conversion.bin": "ea69b1eb", "webgpu/shader/execution/unary/u32_conversion.bin": "2c0e8598",
"webgpu/shader/execution/unary/ai_assignment.bin": "2b40f7c0", "webgpu/shader/execution/unary/ai_assignment.bin": "1302476e",
"webgpu/shader/execution/binary/ai_arithmetic.bin": "65bb3107", "webgpu/shader/execution/binary/ai_arithmetic.bin": "2029b198",
"webgpu/shader/execution/unary/ai_arithmetic.bin": "3dddf016", "webgpu/shader/execution/unary/ai_arithmetic.bin": "9622dbf2",
"webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin": "f904c739", "webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin": "a7e239c4",
"webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin": "7613eb4e", "webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin": "f067a039",
"webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin": "ccc2f487", "webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin": "7936213b",
"webgpu/shader/execution/derivatives.bin": "d70042f3", "webgpu/shader/execution/derivatives.bin": "eda7415f",
"webgpu/shader/execution/fwidth.bin": "224d4da0" "webgpu/shader/execution/fwidth.bin": "1b331b33"
} }

View File

@@ -3,9 +3,10 @@ Stress tests covering robustness in the presence of slow shaders.
`; `;
import { makeTestGroup } from '../../common/framework/test_group.js'; import { makeTestGroup } from '../../common/framework/test_group.js';
import { GPUTest, TextureTestMixin } from '../../webgpu/gpu_test.js'; import { GPUTest } from '../../webgpu/gpu_test.js';
import * as ttu from '../../webgpu/texture_test_utils.js';
export const g = makeTestGroup(TextureTestMixin(GPUTest)); export const g = makeTestGroup(GPUTest);
g.test('compute') g.test('compute')
.desc(`Tests execution of compute passes with very long-running dispatch operations.`) .desc(`Tests execution of compute passes with very long-running dispatch operations.`)
@@ -110,7 +111,7 @@ g.test('vertex')
pass.draw(1); pass.draw(1);
pass.end(); pass.end();
t.device.queue.submit([encoder.finish()]); t.device.queue.submit([encoder.finish()]);
t.expectSinglePixelComparisonsAreOkInTexture({ texture: renderTarget }, [ ttu.expectSinglePixelComparisonsAreOkInTexture(t, { texture: renderTarget }, [
{ {
coord: { x: 1, y: 1 }, coord: { x: 1, y: 1 },
exp: new Uint8Array([255, 255, 0, 255]), exp: new Uint8Array([255, 255, 0, 255]),
@@ -182,7 +183,7 @@ g.test('fragment')
pass.draw(1); pass.draw(1);
pass.end(); pass.end();
t.device.queue.submit([encoder.finish()]); t.device.queue.submit([encoder.finish()]);
t.expectSinglePixelComparisonsAreOkInTexture({ texture: renderTarget }, [ ttu.expectSinglePixelComparisonsAreOkInTexture(t, { texture: renderTarget }, [
{ {
coord: { x: 1, y: 1 }, coord: { x: 1, y: 1 },
exp: new Uint8Array([255, 255, 0, 255]), exp: new Uint8Array([255, 255, 0, 255]),

View File

@@ -4045,9 +4045,26 @@ const kAdditionInterval64BitsNormalCases = {
// f32 0xBDCCCCCD+0xBDCCCCCD=0xBE4CCCCD, 0xBDCCCCCC+0xBDCCCCCC=0xBE4CCCCD // f32 0xBDCCCCCD+0xBDCCCCCD=0xBE4CCCCD, 0xBDCCCCCC+0xBDCCCCCC=0xBE4CCCCD
{ input: [-0.1, -0.1], expected: [reinterpretU32AsF32(0xbe4ccccd), reinterpretU32AsF32(0xbe4ccccc)] }, // ~-0.2 { input: [-0.1, -0.1], expected: [reinterpretU32AsF32(0xbe4ccccd), reinterpretU32AsF32(0xbe4ccccc)] }, // ~-0.2
// 0.1+(-0.1) expect f32 interval [0x3DCCCCCC+0xBDCCCCCD, 0x3DCCCCCD+0xBDCCCCCC] // 0.1+(-0.1) expect f32 interval [0x3DCCCCCC+0xBDCCCCCD, 0x3DCCCCCD+0xBDCCCCCC]
{ input: [0.1, -0.1], expected: [reinterpretU32AsF32(0x3dcccccc)+reinterpretU32AsF32(0xbdcccccd), reinterpretU32AsF32(0x3dcccccd)+reinterpretU32AsF32(0xbdcccccc)] }, // ~0.0 { input: [0.1, -0.1], expected: [reinterpretU32AsF32(0x3dcccccc) + reinterpretU32AsF32(0xbdcccccd), reinterpretU32AsF32(0x3dcccccd) + reinterpretU32AsF32(0xbdcccccc)] }, // ~0.0
// -0.1+0.1 expect f32 interval [0xBDCCCCCD+0x3DCCCCCC, 0xBDCCCCCC+0x3DCCCCCD] // -0.1+0.1 expect f32 interval [0xBDCCCCCD+0x3DCCCCCC, 0xBDCCCCCC+0x3DCCCCCD]
{ input: [-0.1, 0.1], expected: [reinterpretU32AsF32(0xbdcccccd)+reinterpretU32AsF32(0x3dcccccc), reinterpretU32AsF32(0xbdcccccc)+reinterpretU32AsF32(0x3dcccccd)] }, // ~0.0 { input: [-0.1, 0.1], expected: [reinterpretU32AsF32(0xbdcccccd) + reinterpretU32AsF32(0x3dcccccc), reinterpretU32AsF32(0xbdcccccc) + reinterpretU32AsF32(0x3dcccccd)] }, // ~0.0
{ input: [1, kValue.f32.positive.min], expected: [1.0, reinterpretU32AsF32(0x3f800001)] },
{ input: [1, kValue.f32.negative.max], expected: [reinterpretU32AsF32(0x3f7fffff), 1.0] },
{ input: [-1, kValue.f32.positive.min], expected: [-1.0, reinterpretU32AsF32(0xbf7fffff)] },
{ input: [-1, kValue.f32.negative.max], expected: [reinterpretU32AsF32(0xbf800001), -1.0] },
{ input: [1, kValue.f32.positive.max], expected: kUnboundedEndpoints },
{ input: [1, kValue.f32.negative.min], expected: [reinterpretU32AsF32(0xff7fffff), reinterpretU32AsF32(0xff7ffffe)] },
{ input: [-1, kValue.f32.positive.max], expected: [reinterpretU32AsF32(0x7f7ffffe), reinterpretU32AsF32(0x7f7fffff)] },
{ input: [-1, kValue.f32.negative.min], expected: kUnboundedEndpoints },
// Symmetry with the above test cases.
{ input: [kValue.f32.positive.min, 1], expected: [1.0, reinterpretU32AsF32(0x3f800001)] },
{ input: [kValue.f32.negative.max, 1], expected: [reinterpretU32AsF32(0x3f7fffff), 1.0] },
{ input: [kValue.f32.positive.min, -1], expected: [-1.0, reinterpretU32AsF32(0xbf7fffff)] },
{ input: [kValue.f32.negative.max, -1], expected: [reinterpretU32AsF32(0xbf800001), -1.0] },
{ input: [kValue.f32.positive.max, 1], expected: kUnboundedEndpoints },
{ input: [kValue.f32.negative.min, 1], expected: [reinterpretU32AsF32(0xff7fffff), reinterpretU32AsF32(0xff7ffffe)] },
{ input: [kValue.f32.positive.max, -1], expected: [reinterpretU32AsF32(0x7f7ffffe), reinterpretU32AsF32(0x7f7fffff)] },
{ input: [kValue.f32.negative.min, -1], expected: kUnboundedEndpoints },
] as ScalarPairToIntervalCase[], ] as ScalarPairToIntervalCase[],
f16: [ f16: [
// 0.1 falls between f16 0x2E66 and 0x2E67, -0.1 falls between f16 0xAE67 and 0xAE66 // 0.1 falls between f16 0x2E66 and 0x2E67, -0.1 falls between f16 0xAE67 and 0xAE66
@@ -4056,7 +4073,7 @@ const kAdditionInterval64BitsNormalCases = {
// f16 0xAE67+0xAE67=0xB267, 0xAE66+0xAE66=0xB266 // f16 0xAE67+0xAE67=0xB267, 0xAE66+0xAE66=0xB266
{ input: [-0.1, -0.1], expected: [reinterpretU16AsF16(0xb267), reinterpretU16AsF16(0xb266)] }, // ~-0.2 { input: [-0.1, -0.1], expected: [reinterpretU16AsF16(0xb267), reinterpretU16AsF16(0xb266)] }, // ~-0.2
// 0.1+(-0.1) expect f16 interval [0x2E66+0xAE67, 0x2E67+0xAE66] // 0.1+(-0.1) expect f16 interval [0x2E66+0xAE67, 0x2E67+0xAE66]
{ input: [0.1, -0.1], expected: [reinterpretU16AsF16(0x2e66)+reinterpretU16AsF16(0xae67), reinterpretU16AsF16(0x2e67)+reinterpretU16AsF16(0xae66)] }, // ~0.0 { input: [0.1, -0.1], expected: [reinterpretU16AsF16(0x2e66) + reinterpretU16AsF16(0xae67), reinterpretU16AsF16(0x2e67) + reinterpretU16AsF16(0xae66)] }, // ~0.0
// -0.1+0.1 expect f16 interval [0xAE67+0x2E66, 0xAE66+0x2E67] // -0.1+0.1 expect f16 interval [0xAE67+0x2E66, 0xAE66+0x2E67]
{ input: [-0.1, 0.1], expected: [reinterpretU16AsF16(0xae67)+reinterpretU16AsF16(0x2e66), reinterpretU16AsF16(0xae66)+reinterpretU16AsF16(0x2e67)] }, // ~0.0 { input: [-0.1, 0.1], expected: [reinterpretU16AsF16(0xae67)+reinterpretU16AsF16(0x2e66), reinterpretU16AsF16(0xae66)+reinterpretU16AsF16(0x2e67)] }, // ~0.0
] as ScalarPairToIntervalCase[], ] as ScalarPairToIntervalCase[],
@@ -5017,6 +5034,23 @@ const kSubtractionInterval64BitsNormalCases = {
{ input: [0.1, -0.1], expected: [reinterpretU32AsF32(0x3dcccccc)-reinterpretU32AsF32(0xbdcccccc), reinterpretU32AsF32(0x3dcccccd)-reinterpretU32AsF32(0xbdcccccd)] }, { input: [0.1, -0.1], expected: [reinterpretU32AsF32(0x3dcccccc)-reinterpretU32AsF32(0xbdcccccc), reinterpretU32AsF32(0x3dcccccd)-reinterpretU32AsF32(0xbdcccccd)] },
// Expect f32 interval [0xBDCCCCCD-0x3DCCCCCD, 0xBDCCCCCC-0x3DCCCCCC] // Expect f32 interval [0xBDCCCCCD-0x3DCCCCCD, 0xBDCCCCCC-0x3DCCCCCC]
{ input: [-0.1, 0.1], expected: [reinterpretU32AsF32(0xbdcccccd)-reinterpretU32AsF32(0x3dcccccd), reinterpretU32AsF32(0xbdcccccc)-reinterpretU32AsF32(0x3dcccccc)] }, { input: [-0.1, 0.1], expected: [reinterpretU32AsF32(0xbdcccccd)-reinterpretU32AsF32(0x3dcccccd), reinterpretU32AsF32(0xbdcccccc)-reinterpretU32AsF32(0x3dcccccc)] },
{ input: [1, kValue.f32.positive.min], expected: [reinterpretU32AsF32(0x3f7fffff), 1.0] },
{ input: [1, kValue.f32.negative.max], expected: [ 1.0, reinterpretU32AsF32(0x3f800001)] },
{ input: [-1, kValue.f32.positive.min], expected: [reinterpretU32AsF32(0xbf800001), -1.0] },
{ input: [-1, kValue.f32.negative.max], expected: [-1.0, reinterpretU32AsF32(0xbf7fffff)] },
{ input: [1, kValue.f32.positive.max], expected: [reinterpretU32AsF32(0xff7fffff), reinterpretU32AsF32(0xff7ffffe)]},
{ input: [1, kValue.f32.negative.min], expected: kUnboundedEndpoints},
{ input: [-1, kValue.f32.positive.max], expected:kUnboundedEndpoints},
{ input: [-1, kValue.f32.negative.min], expected: [reinterpretU32AsF32(0x7f7ffffe) , reinterpretU32AsF32(0x7f7fffff)] },
// Symmetric with above (expected will be anti-symmetric)
{ input: [kValue.f32.positive.min, 1], expected: [-1.0 , reinterpretU32AsF32(0xbf7fffff)] },
{ input: [kValue.f32.negative.max, 1], expected: [reinterpretU32AsF32(0xbf800001), -1.0] },
{ input: [kValue.f32.positive.min, -1], expected: [1.0, reinterpretU32AsF32(0x3f800001)] },
{ input: [kValue.f32.negative.max, -1], expected: [reinterpretU32AsF32(0x3f7fffff), 1.0] },
{ input: [kValue.f32.positive.max, 1], expected: [reinterpretU32AsF32(0x7f7ffffe), reinterpretU32AsF32(0x7f7fffff)]},
{ input: [kValue.f32.negative.min, 1], expected: kUnboundedEndpoints},
{ input: [kValue.f32.positive.max, -1], expected:kUnboundedEndpoints},
{ input: [kValue.f32.negative.min, -1], expected: [reinterpretU32AsF32(0xff7fffff) , reinterpretU32AsF32(0xff7ffffe)] },
] as ScalarPairToIntervalCase[], ] as ScalarPairToIntervalCase[],
f16: [ f16: [
// 0.1 falls between f16 0x2E66 and 0x2E67, -0.1 falls between f16 0xAE67 and 0xAE66 // 0.1 falls between f16 0x2E66 and 0x2E67, -0.1 falls between f16 0xAE67 and 0xAE66
@@ -5330,16 +5364,18 @@ const kMixImpreciseIntervalCases = {
{ input: [-1.0, 1.0, 0.9], expected: [reinterpretU64AsF64(0x3fe9_9999_8000_0000n), reinterpretU64AsF64(0x3fe9_9999_c000_0000n)] }, // ~0.8 { input: [-1.0, 1.0, 0.9], expected: [reinterpretU64AsF64(0x3fe9_9999_8000_0000n), reinterpretU64AsF64(0x3fe9_9999_c000_0000n)] }, // ~0.8
// Showing how precise and imprecise versions diff // Showing how precise and imprecise versions diff
// Note that this expectation is 0 in f32 as |10.0| is much smaller than // Note that this expectation is unbounded [-inf,inf] in f32 as |10.0| is much smaller than
// |f32.negative.min|. // |f32.negative.min|. The implementation of imprecise is is := x + (y - x) * z
// So that 10 - f32.negative.min == -f32.negative.min even in f64. // So that 10 - f32.negative.min == [f32.positive.max, inf] due to correctly rounding of unbounded precision.
{ input: [kValue.f32.negative.min, 10.0, 1.0], expected: 0.0 }, { input: [kValue.f32.negative.min, 10.0, 1.0], expected: kUnboundedEndpoints},
// -10.0 is the same, much smaller than f32.negative.min // -10.0 is the same, however due to smaller than f32.negative.min we end up with [ULP_neg(f32.positive.max), f32.positive.max]
{ input: [kValue.f32.negative.min, -10.0, 1.0], expected: 0.0 }, { input: [kValue.f32.negative.min, -10.0, 1.0], expected: [reinterpretU32AsF32(0xf3800000), 0.0] },
{ input: [kValue.f32.negative.min, 10.0, 5.0], expected: kUnboundedEndpoints }, { input: [kValue.f32.negative.min, 10.0, 5.0], expected: kUnboundedEndpoints },
{ input: [kValue.f32.negative.min, -10.0, 5.0], expected: kUnboundedEndpoints }, { input: [kValue.f32.negative.min, -10.0, 5.0], expected: kUnboundedEndpoints },
{ input: [kValue.f32.negative.min, 10.0, 0.5], expected: reinterpretU32AsF32(0xfeffffff) }, { input: [kValue.f32.negative.min, 10.0, 0.5], expected: kUnboundedEndpoints },
{ input: [kValue.f32.negative.min, -10.0, 0.5], expected: reinterpretU32AsF32(0xfeffffff) }, { input: [kValue.f32.negative.min, -10.0, 0.5], expected: [reinterpretU32AsF32(0xff000000), reinterpretU32AsF32(0xfeffffff) ]},
// Test the case of unbounded precision of mix when implementing the subtraction intermediate value.
{ input: [kValue.f32.positive.min, 1.0, kValue.f32.positive.min], expected: [reinterpretU32AsF32(0x00800000),reinterpretU32AsF32(0x01000000)]},
] as ScalarTripleToIntervalCase[], ] as ScalarTripleToIntervalCase[],
f16: [ f16: [
// [0.0, 1.0] cases // [0.0, 1.0] cases
@@ -5470,8 +5506,8 @@ const kMixPreciseIntervalCases = {
{ input: [kValue.f32.negative.min, -10.0, 1.0], expected: -10 }, { input: [kValue.f32.negative.min, -10.0, 1.0], expected: -10 },
{ input: [kValue.f32.negative.min, 10.0, 5.0], expected: kUnboundedEndpoints }, { input: [kValue.f32.negative.min, 10.0, 5.0], expected: kUnboundedEndpoints },
{ input: [kValue.f32.negative.min, -10.0, 5.0], expected: kUnboundedEndpoints }, { input: [kValue.f32.negative.min, -10.0, 5.0], expected: kUnboundedEndpoints },
{ input: [kValue.f32.negative.min, 10.0, 0.5], expected: reinterpretU32AsF32(0xfeffffff) }, { input: [kValue.f32.negative.min, 10.0, 0.5], expected: [reinterpretU32AsF32(0xfeffffff), reinterpretU32AsF32(0xfefffffe) ] },
{ input: [kValue.f32.negative.min, -10.0, 0.5], expected: reinterpretU32AsF32(0xfeffffff) }, { input: [kValue.f32.negative.min, -10.0, 0.5], expected: [reinterpretU32AsF32(0xff000000),reinterpretU32AsF32(0xfeffffff) ] },
// Intermediate OOB // Intermediate OOB
{ input: [1.0, 2.0, kPlusOneULPFunctions['f32'](kValue.f32.positive.max / 2)], expected: kUnboundedEndpoints }, { input: [1.0, 2.0, kPlusOneULPFunctions['f32'](kValue.f32.positive.max / 2)], expected: kUnboundedEndpoints },
@@ -5595,10 +5631,10 @@ const kSmoothStepIntervalCases = {
{ input: [0, -2, -1], expected: [reinterpretU32AsF32(0x3efffff8), reinterpretU32AsF32(0x3f000007)] }, // ~0.5 { input: [0, -2, -1], expected: [reinterpretU32AsF32(0x3efffff8), reinterpretU32AsF32(0x3f000007)] }, // ~0.5
{ input: [0, -2, -0.5], expected: [reinterpretU32AsF32(0x3e1ffffb), reinterpretU32AsF32(0x3e200007)] }, // ~0.15625... { input: [0, -2, -0.5], expected: [reinterpretU32AsF32(0x3e1ffffb), reinterpretU32AsF32(0x3e200007)] }, // ~0.15625...
// Subnormals // Subnormals
{ input: [kValue.f32.positive.subnormal.max, 2, 1], expected: [reinterpretU32AsF32(0x3efffff8), reinterpretU32AsF32(0x3f000007)] }, // ~0.5 { input: [kValue.f32.positive.subnormal.max, 2, 1], expected: [reinterpretU32AsF32(0x3efffff4), reinterpretU32AsF32(0x3f00000b)] }, // ~0.5
{ input: [kValue.f32.positive.subnormal.min, 2, 1], expected: [reinterpretU32AsF32(0x3efffff8), reinterpretU32AsF32(0x3f000007)] }, // ~0.5 { input: [kValue.f32.positive.subnormal.min, 2, 1], expected: [reinterpretU32AsF32(0x3efffff4), reinterpretU32AsF32(0x3f00000b)] }, // ~0.5
{ input: [kValue.f32.negative.subnormal.max, 2, 1], expected: [reinterpretU32AsF32(0x3efffff8), reinterpretU32AsF32(0x3f000007)] }, // ~0.5 { input: [kValue.f32.negative.subnormal.max, 2, 1], expected: [reinterpretU32AsF32(0x3efffff2), reinterpretU32AsF32(0x3f00000c)] }, // ~0.5
{ input: [kValue.f32.negative.subnormal.min, 2, 1], expected: [reinterpretU32AsF32(0x3efffff8), reinterpretU32AsF32(0x3f000007)] }, // ~0.5 { input: [kValue.f32.negative.subnormal.min, 2, 1], expected: [reinterpretU32AsF32(0x3efffff2), reinterpretU32AsF32(0x3f00000c)] }, // ~0.5
{ input: [0, 2, kValue.f32.positive.subnormal.max], expected: [0, kValue.f32.positive.subnormal.min] }, { input: [0, 2, kValue.f32.positive.subnormal.max], expected: [0, kValue.f32.positive.subnormal.min] },
{ input: [0, 2, kValue.f32.positive.subnormal.min], expected: [0, kValue.f32.positive.subnormal.min] }, { input: [0, 2, kValue.f32.positive.subnormal.min], expected: [0, kValue.f32.positive.subnormal.min] },
{ input: [0, 2, kValue.f32.negative.subnormal.max], expected: [0, kValue.f32.positive.subnormal.min] }, { input: [0, 2, kValue.f32.negative.subnormal.max], expected: [0, kValue.f32.positive.subnormal.min] },
@@ -5608,10 +5644,10 @@ const kSmoothStepIntervalCases = {
{ input: [1, 0, 1], expected: [0, kValue.f32.positive.subnormal.min] }, { input: [1, 0, 1], expected: [0, kValue.f32.positive.subnormal.min] },
{ input: [1, 0, 0], expected: [reinterpretU32AsF32(0x3f7ffffa), reinterpretU32AsF32(0x3f800003)] }, // ~1 { input: [1, 0, 0], expected: [reinterpretU32AsF32(0x3f7ffffa), reinterpretU32AsF32(0x3f800003)] }, // ~1
// Subnormals // Subnormals
{ input: [2, kValue.f32.positive.subnormal.max, 1], expected: [reinterpretU32AsF32(0x3efffff8), reinterpretU32AsF32(0x3f000007)] }, // ~0.5 { input: [2, kValue.f32.positive.subnormal.max, 1], expected: [reinterpretU32AsF32(0x3efffff6), reinterpretU32AsF32(0x3f00000b)] }, // ~0.5
{ input: [2, kValue.f32.positive.subnormal.min, 1], expected: [reinterpretU32AsF32(0x3efffff8), reinterpretU32AsF32(0x3f000007)] }, // ~0.5 { input: [2, kValue.f32.positive.subnormal.min, 1], expected: [reinterpretU32AsF32(0x3efffff6), reinterpretU32AsF32(0x3f00000b)] }, // ~0.5
{ input: [2, kValue.f32.negative.subnormal.max, 1], expected: [reinterpretU32AsF32(0x3efffff8), reinterpretU32AsF32(0x3f000007)] }, // ~0.5 { input: [2, kValue.f32.negative.subnormal.max, 1], expected: [reinterpretU32AsF32(0x3efffff4), reinterpretU32AsF32(0x3f000008)] }, // ~0.5
{ input: [2, kValue.f32.negative.subnormal.min, 1], expected: [reinterpretU32AsF32(0x3efffff8), reinterpretU32AsF32(0x3f000007)] }, // ~0.5 { input: [2, kValue.f32.negative.subnormal.min, 1], expected: [reinterpretU32AsF32(0x3efffff4), reinterpretU32AsF32(0x3f000008)] }, // ~0.5
] as ScalarTripleToIntervalCase[], ] as ScalarTripleToIntervalCase[],
f16: [ f16: [
// Normals // Normals
@@ -6056,14 +6092,16 @@ g.test('distanceIntervalVector')
// prettier-ignore // prettier-ignore
const kDotIntervalCases = { const kDotIntervalCases = {
f32: [ f32: [
// Inputs with large values but cancel out to finite result. In these cases, 2.0*2.0 = 4.0 and // Due to unbounded precision, intermediate correctly rounded computations could result in intervals that include infinity.
// 3.0*3.0 = 9.0 is much smaller than kValue.f32.positive.max, as a result // This is because the computation kValue.f32.negative.min - 4.0 = [-inf, kValue.f32.negative.min]
// kValue.f32.positive.max + 9.0 = kValue.f32.positive.max in f32 and even f64. So, if the // due to the ULP_neg(kValue.f32.negative.min) => -inf
// positive and negative large number cancel each other first, the result would be // See: https://www.w3.org/TR/WGSL/#floating-point-accuracy
// 2.0*2.0+3.0*3.0 = 13. Otherwise, the result would be 0.0 or 4.0 or 9.0. { input: [[kValue.f32.positive.max, 1.0, 2.0, 3.0], [-1.0, kValue.f32.positive.max, -2.0, -3.0]], expected: kUnboundedEndpoints},
// https://github.com/gpuweb/cts/issues/2155 { input: [[kValue.f32.positive.max, 1.0, 2.0, 3.0], [1.0, kValue.f32.negative.min, 2.0, 3.0]], expected: kUnboundedEndpoints },
{ input: [[kValue.f32.positive.max, 1.0, 2.0, 3.0], [-1.0, kValue.f32.positive.max, -2.0, -3.0]], expected: [-13, 0] }, // Exactly as above but simply 2 ulp magnitude smaller (away from kValue.f32.positive.max).
{ input: [[kValue.f32.positive.max, 1.0, 2.0, 3.0], [1.0, kValue.f32.negative.min, 2.0, 3.0]], expected: [0, 13] }, // This avoids intermediate intervals that overflow into infinity and we end up with large but finite intervals.
{ input: [[reinterpretU32AsF32(0x7f7ffffd), 1.0, 2.0, 3.0], [-1.0, kValue.f32.positive.max, -2.0, -3.0]], expected: [0.0, reinterpretU32AsF32(0x74000000)]},
{ input: [[reinterpretU32AsF32(0x7f7ffffd), 1.0, 2.0, 3.0], [1.0, kValue.f32.negative.min, 2.0, 3.0]], expected: [reinterpretU32AsF32(0xf4000000), 0.0] },
] as VectorPairToIntervalCase[], ] as VectorPairToIntervalCase[],
f16: [ f16: [
// Inputs with large values but cancel out to finite result. In these cases, 2.0*2.0 = 4.0 and // Inputs with large values but cancel out to finite result. In these cases, 2.0*2.0 = 4.0 and

View File

@@ -173,20 +173,8 @@ g.test('stale')
); );
} }
const kTimeoutMS = 1000; // Since the adapter is consumed now, requesting another device is not possible anymore.
const lostDevice = await t.requestDeviceTracked(adapter); t.shouldReject('OperationError', t.requestDeviceTracked(adapter));
const lost = await raceWithRejectOnTimeout(
lostDevice.lost,
kTimeoutMS,
'adapter was not stale'
);
t.expect(lost.reason === 'unknown');
// Make sure to destroy the valid device after trying to get a second one. Otherwise, the second
// device may fail because the adapter is put into an invalid state from the destroy.
if (device) {
device.destroy();
}
}); });
g.test('features,unknown') g.test('features,unknown')

View File

@@ -24,7 +24,8 @@ import {
textureDimensionAndFormatCompatible, textureDimensionAndFormatCompatible,
textureFormatsAreViewCompatible, textureFormatsAreViewCompatible,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { checkElementsEqual } from '../../../util/check_contents.js'; import { checkElementsEqual } from '../../../util/check_contents.js';
import { align } from '../../../util/math.js'; import { align } from '../../../util/math.js';
import { physicalMipSize } from '../../../util/texture/base.js'; import { physicalMipSize } from '../../../util/texture/base.js';
@@ -35,7 +36,7 @@ import { findFailedPixels } from '../../../util/texture/texture_ok.js';
const dataGenerator = new DataArrayGenerator(); const dataGenerator = new DataArrayGenerator();
class F extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) { class F extends AllFeaturesMaxLimitsGPUTest {
GetInitialDataPerMipLevel( GetInitialDataPerMipLevel(
dimension: GPUTextureDimension, dimension: GPUTextureDimension,
textureSize: Required<GPUExtent3DDict>, textureSize: Required<GPUExtent3DDict>,
@@ -220,7 +221,7 @@ class F extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
// Execute the equivalent of `copyTextureToTexture`, copying // Execute the equivalent of `copyTextureToTexture`, copying
// from `initialSrcData` to `expectedData`. // from `initialSrcData` to `expectedData`.
this.updateLinearTextureDataSubBox(dstFormat, appliedSize, { ttu.updateLinearTextureDataSubBox(this, dstFormat, appliedSize, {
src: { src: {
dataLayout: { dataLayout: {
bytesPerRow: srcBlocksPerRow * bytesPerBlock, bytesPerRow: srcBlocksPerRow * bytesPerBlock,
@@ -253,7 +254,8 @@ class F extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
dstTextureSizeAtLevel dstTextureSizeAtLevel
); );
this.expectTexturesToMatchByRendering( ttu.expectTexturesToMatchByRendering(
this,
dstTexture, dstTexture,
expectedTexture, expectedTexture,
dstCopyLevel, dstCopyLevel,

View File

@@ -60,7 +60,8 @@ import {
canCopyToAllAspectsOfTextureFormat, canCopyToAllAspectsOfTextureFormat,
canCopyFromAllAspectsOfTextureFormat, canCopyFromAllAspectsOfTextureFormat,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { checkElementsEqual } from '../../../util/check_contents.js'; import { checkElementsEqual } from '../../../util/check_contents.js';
import { align } from '../../../util/math.js'; import { align } from '../../../util/math.js';
import { physicalMipSizeFromTexture } from '../../../util/texture/base.js'; import { physicalMipSizeFromTexture } from '../../../util/texture/base.js';
@@ -125,7 +126,7 @@ const kMethodsToTest = [
const dataGenerator = new DataArrayGenerator(); const dataGenerator = new DataArrayGenerator();
const altDataGenerator = new DataArrayGenerator(); const altDataGenerator = new DataArrayGenerator();
class ImageCopyTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) { class ImageCopyTest extends AllFeaturesMaxLimitsGPUTest {
/** /**
* This is used for testing passing undefined members of `GPUTexelCopyBufferLayout` instead of actual * This is used for testing passing undefined members of `GPUTexelCopyBufferLayout` instead of actual
* values where possible. Passing arguments as values and not as objects so that they are passed * values where possible. Passing arguments as values and not as objects so that they are passed
@@ -292,8 +293,8 @@ class ImageCopyTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
{ {
const rowLength = bytesInACompleteRow(size.width, format); const rowLength = bytesInACompleteRow(size.width, format);
let lastOffset = 0; let lastOffset = 0;
for (const texel of this.iterateBlockRows(size, format)) { for (const texel of ttu.iterateBlockRows(size, format)) {
const offset = this.getTexelOffsetInBytes(dataLayout, format, texel, zero); const offset = ttu.getTexelOffsetInBytes(dataLayout, format, texel, zero);
const actualPart = actual.subarray(lastOffset, offset); const actualPart = actual.subarray(lastOffset, offset);
const expectedPart = expected.subarray(lastOffset, offset); const expectedPart = expected.subarray(lastOffset, offset);
const error = checkElementsEqual(actualPart, expectedPart); const error = checkElementsEqual(actualPart, expectedPart);
@@ -467,7 +468,7 @@ class ImageCopyTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
// update the data for the entire mip level with the data // update the data for the entire mip level with the data
// that would be copied to the "actual" texture // that would be copied to the "actual" texture
this.updateLinearTextureDataSubBox(format, copySize, { ttu.updateLinearTextureDataSubBox(this, format, copySize, {
src: { src: {
dataLayout: expectedDataLayout, dataLayout: expectedDataLayout,
origin: { x: 0, y: 0, z: 0 }, origin: { x: 0, y: 0, z: 0 },
@@ -488,7 +489,8 @@ class ImageCopyTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
mipSize mipSize
); );
this.expectTexturesToMatchByRendering( ttu.expectTexturesToMatchByRendering(
this,
actualTexture, actualTexture,
expectedTexture, expectedTexture,
mipLevel, mipLevel,
@@ -542,7 +544,7 @@ class ImageCopyTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
// bufferData has ...... in it. // bufferData has ...... in it.
// Update bufferData to have the same contents as buffer. // Update bufferData to have the same contents as buffer.
// When done, bufferData now has t.t.t. because the rows are padded. // When done, bufferData now has t.t.t. because the rows are padded.
this.updateLinearTextureDataSubBox(format, checkSize, { ttu.updateLinearTextureDataSubBox(this, format, checkSize, {
src: { src: {
dataLayout: expectedDataLayout, dataLayout: expectedDataLayout,
origin: { x: 0, y: 0, z: 0 }, origin: { x: 0, y: 0, z: 0 },
@@ -592,7 +594,7 @@ class ImageCopyTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
// other eventual async expectations to ensure it will be correct. // other eventual async expectations to ensure it will be correct.
this.eventualAsyncExpectation(async () => { this.eventualAsyncExpectation(async () => {
const readback = await readbackPromise; const readback = await readbackPromise;
this.updateLinearTextureDataSubBox(format, copySize, { ttu.updateLinearTextureDataSubBox(this, format, copySize, {
dest: { dest: {
dataLayout: { offset: 0, ...fullTextureCopyLayout }, dataLayout: { offset: 0, ...fullTextureCopyLayout },
origin, origin,
@@ -701,7 +703,8 @@ class ImageCopyTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
mipLevel, mipLevel,
}); });
const fullData = this.copyWholeTextureToNewBuffer( const fullData = ttu.copyWholeTextureToNewBuffer(
this,
{ texture, mipLevel }, { texture, mipLevel },
fullTextureCopyLayout fullTextureCopyLayout
); );

View File

@@ -6,10 +6,11 @@ Equivalent tests for viewport/scissor/blend/reference are in render/dynamic_stat
`; `;
import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js';
import * as ttu from '../../../../texture_test_utils.js';
import { TexelView } from '../../../../util/texture/texel_view.js'; import { TexelView } from '../../../../util/texture/texel_view.js';
class VertexAndIndexStateTrackingTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) { class VertexAndIndexStateTrackingTest extends AllFeaturesMaxLimitsGPUTest {
GetRenderPipelineForTest(arrayStride: number): GPURenderPipeline { GetRenderPipelineForTest(arrayStride: number): GPURenderPipeline {
return this.device.createRenderPipeline({ return this.device.createRenderPipeline({
layout: 'auto', layout: 'auto',
@@ -171,7 +172,8 @@ g.test('set_index_buffer_without_changing_buffer')
renderPass.end(); renderPass.end();
t.queue.submit([encoder.finish()]); t.queue.submit([encoder.finish()]);
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: outputTexture }, { texture: outputTexture },
TexelView.fromTexelsAsBytes('rgba8unorm', coord => TexelView.fromTexelsAsBytes('rgba8unorm', coord =>
coord.x === 1 ? kColors[kPositions.length - 1] : kColors[coord.x] coord.x === 1 ? kColors[kPositions.length - 1] : kColors[coord.x]
@@ -274,7 +276,8 @@ g.test('set_vertex_buffer_without_changing_buffer')
renderPass.end(); renderPass.end();
t.queue.submit([encoder.finish()]); t.queue.submit([encoder.finish()]);
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: outputTexture }, { texture: outputTexture },
TexelView.fromTexelsAsBytes('rgba8unorm', coord => kColors[coord.x]), TexelView.fromTexelsAsBytes('rgba8unorm', coord => kColors[coord.x]),
outputTextureSize outputTextureSize
@@ -358,7 +361,8 @@ g.test('change_pipeline_before_and_after_vertex_buffer')
t.queue.submit([encoder.finish()]); t.queue.submit([encoder.finish()]);
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: outputTexture }, { texture: outputTexture },
TexelView.fromTexelsAsBytes('rgba8unorm', coord => TexelView.fromTexelsAsBytes('rgba8unorm', coord =>
coord.x === 1 ? new Uint8Array([0, 0, 0, 255]) : kColors[coord.x] coord.x === 1 ? new Uint8Array([0, 0, 0, 255]) : kColors[coord.x]
@@ -536,7 +540,8 @@ g.test('set_vertex_buffer_but_not_used_in_draw')
kColors.subarray(4), kColors.subarray(4),
]; ];
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: outputTexture }, { texture: outputTexture },
TexelView.fromTexelsAsBytes('rgba8unorm', coord => kExpectedColors[coord.x]), TexelView.fromTexelsAsBytes('rgba8unorm', coord => kExpectedColors[coord.x]),
outputTextureSize outputTextureSize
@@ -612,7 +617,8 @@ g.test('set_index_buffer_before_non_indexed_draw')
t.queue.submit([encoder.finish()]); t.queue.submit([encoder.finish()]);
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: outputTexture }, { texture: outputTexture },
TexelView.fromTexelsAsBytes('rgba8unorm', coord => kColors[coord.x]), TexelView.fromTexelsAsBytes('rgba8unorm', coord => kColors[coord.x]),
outputTextureSize outputTextureSize

View File

@@ -12,10 +12,11 @@ implementation allows, all of them are useable.
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { range } from '../../../../common/util/util.js'; import { range } from '../../../../common/util/util.js';
import { getColorRenderByteCost } from '../../../format_info.js'; import { getColorRenderByteCost } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { TexelView } from '../../../util/texture/texel_view.js'; import { TexelView } from '../../../util/texture/texel_view.js';
export const g = makeTestGroup(TextureTestMixin(AllFeaturesMaxLimitsGPUTest)); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('max_storage_buffer_texture_frag_outputs') g.test('max_storage_buffer_texture_frag_outputs')
.desc( .desc(
@@ -198,7 +199,8 @@ ${range(numColorAttachments, i => ` fragOut.f${i} = vec4u(p + ${i} * 3);`).join
}); });
storageTextures.forEach((texture, i) => { storageTextures.forEach((texture, i) => {
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture }, { texture },
TexelView.fromTextureDataByReference( TexelView.fromTextureDataByReference(
'rgba32uint', 'rgba32uint',
@@ -231,7 +233,8 @@ ${range(numColorAttachments, i => ` fragOut.f${i} = vec4u(p + ${i} * 3);`).join
bytesPerRow = kWidth * 16; bytesPerRow = kWidth * 16;
break; break;
} }
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture }, { texture },
TexelView.fromTextureDataByReference(format, expected, { TexelView.fromTextureDataByReference(format, expected, {
bytesPerRow, bytesPerRow,

View File

@@ -13,10 +13,6 @@ import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('stored')
.desc(`Test render pass clear values are stored at the end of an empty pass.`)
.unimplemented();
g.test('loaded') g.test('loaded')
.desc( .desc(
`Test render pass clear values are visible during the pass by doing some trivial blending `Test render pass clear values are visible during the pass by doing some trivial blending
@@ -24,21 +20,6 @@ with the attachment (e.g. add [0,0,0,0] to the color and verify the stored resul
) )
.unimplemented(); .unimplemented();
g.test('srgb')
.desc(
`Test that clear values on '-srgb' type attachments are interpreted as unencoded (linear),
not decoded from srgb to linear.`
)
.unimplemented();
g.test('layout')
.desc(
`Test that bind group layouts of the default pipeline layout are correct by passing various
shaders and then checking their computed bind group layouts are compatible with particular bind
groups.`
)
.unimplemented();
g.test('stencil_clear_value') g.test('stencil_clear_value')
.desc( .desc(
`Test that when stencilLoadOp is "clear", the stencil aspect should be correctly cleared by `Test that when stencilLoadOp is "clear", the stencil aspect should be correctly cleared by

View File

@@ -1,20 +1,8 @@
export const description = `API Operation Tests for RenderPass StoreOp. export const description = `API Operation Tests for multisample resolve in render passes.`;
Tests a render pass with a resolveTarget resolves correctly for many combinations of:
- number of color attachments, some with and some without a resolveTarget
- renderPass storeOp set to {'store', 'discard'}
- resolveTarget mip level {0, >0} (TODO?: different mip level from colorAttachment)
- resolveTarget {2d array layer, TODO: 3d slice} {0, >0} with {2d, TODO: 3d} resolveTarget
(TODO?: different z from colorAttachment)
- TODO: test all renderable color formats
- TODO: test that any not-resolved attachments are rendered to correctly.
- TODO: test different loadOps
- TODO?: resolveTarget mip level {0, >0} (TODO?: different mip level from colorAttachment)
- TODO?: resolveTarget {2d array layer, TODO: 3d slice} {0, >0} with {2d, TODO: 3d} resolveTarget
(different z from colorAttachment)
`;
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
const kSlotsToResolve = [ const kSlotsToResolve = [
[0, 2], [0, 2],
@@ -25,11 +13,31 @@ const kSlotsToResolve = [
const kSize = 4; const kSize = 4;
const kFormat: GPUTextureFormat = 'rgba8unorm'; const kFormat: GPUTextureFormat = 'rgba8unorm';
export const g = makeTestGroup(TextureTestMixin(AllFeaturesMaxLimitsGPUTest)); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('render_pass_resolve') g.test('render_pass_resolve')
.desc(
`
Test basic render pass resolve behavior for combinations of:
- number of color attachments, some with and some without a resolveTarget
- {a single draw+resolve pass, one draw-store pass and one empty load-resolve pass}
(attempts to test known driver bugs with empty resolve passes)
- in the resolve pass, storeOp set to {'store', 'discard'}
- mip levels {0, 1} and array layers {0, 1}
TODO: cases where color attachment and resolve target don't have the same mip level
- resolveTarget {2d array layer, TODO: 3d slice} {0, >0} with {2d, TODO: 3d} resolveTarget
TODO: cases where color attachment and resolve target don't have the same z (slice or layer)
- TODO: test all renderable color formats
- TODO: test that any not-resolved attachments are rendered to correctly.
- TODO: test different loadOps
- TODO?: resolveTarget mip level {0, >0} (TODO?: different mip level from colorAttachment)
- TODO?: resolveTarget {2d array layer, TODO: 3d slice} {0, >0} with {2d, TODO: 3d} resolveTarget
(different z from colorAttachment)
`
)
.params(u => .params(u =>
u u
.combine('separateResolvePass', [false, true])
.combine('storeOperation', ['discard', 'store'] as const) .combine('storeOperation', ['discard', 'store'] as const)
.beginSubcases() .beginSubcases()
.combine('numColorAttachments', [2, 4] as const) .combine('numColorAttachments', [2, 4] as const)
@@ -92,61 +100,61 @@ g.test('render_pass_resolve')
}); });
const resolveTargets: GPUTexture[] = []; const resolveTargets: GPUTexture[] = [];
const renderPassColorAttachments: GPURenderPassColorAttachment[] = []; const drawPassAttachments: GPURenderPassColorAttachment[] = [];
const resolvePassAttachments: GPURenderPassColorAttachment[] = [];
// The resolve target must be the same size as the color attachment. If we're resolving to mip // The resolve target must be the same size as the color attachment. If we're resolving to mip
// level 1, the resolve target base mip level should be 2x the color attachment size. // level 1, the resolve target base mip level should be 2x the color attachment size.
const kResolveTargetSize = kSize << t.params.resolveTargetBaseMipLevel; const kResolveTargetSize = kSize << t.params.resolveTargetBaseMipLevel;
for (let i = 0; i < t.params.numColorAttachments; i++) { for (let i = 0; i < t.params.numColorAttachments; i++) {
const colorAttachment = t.createTextureTracked({ const colorAttachment = t
.createTextureTracked({
format: kFormat, format: kFormat,
size: { width: kSize, height: kSize, depthOrArrayLayers: 1 }, size: [kSize, kSize, 1],
sampleCount: 4, sampleCount: 4,
mipLevelCount: 1, mipLevelCount: 1,
usage: usage:
GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT, GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
}); })
.createView();
let resolveTarget: GPUTextureView | undefined;
if (t.params.slotsToResolve.includes(i)) { if (t.params.slotsToResolve.includes(i)) {
const colorAttachment = t.createTextureTracked({ const resolveTargetTexture = t.createTextureTracked({
format: kFormat, format: kFormat,
size: { width: kSize, height: kSize, depthOrArrayLayers: 1 }, size: [kResolveTargetSize, kResolveTargetSize, t.params.resolveTargetBaseArrayLayer + 1],
sampleCount: 4,
mipLevelCount: 1,
usage:
GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
});
const resolveTarget = t.createTextureTracked({
format: kFormat,
size: {
width: kResolveTargetSize,
height: kResolveTargetSize,
depthOrArrayLayers: t.params.resolveTargetBaseArrayLayer + 1,
},
sampleCount: 1, sampleCount: 1,
mipLevelCount: t.params.resolveTargetBaseMipLevel + 1, mipLevelCount: t.params.resolveTargetBaseMipLevel + 1,
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT, usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
}); });
resolveTargets.push(resolveTargetTexture);
resolveTarget = resolveTargetTexture.createView({
baseMipLevel: t.params.resolveTargetBaseMipLevel,
baseArrayLayer: t.params.resolveTargetBaseArrayLayer,
});
}
// Clear to black for the load operation. After the draw, the top left half of the attachment // Clear to black for the load operation. After the draw, the top left half of the attachment
// will be white and the bottom right half will be black. // will be white and the bottom right half will be black.
renderPassColorAttachments.push({ if (t.params.separateResolvePass) {
view: colorAttachment.createView(), drawPassAttachments.push({
view: colorAttachment,
clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }, clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 0.0 },
loadOp: 'clear', loadOp: 'clear',
storeOp: t.params.storeOperation, storeOp: 'store',
resolveTarget: resolveTarget.createView({ });
baseMipLevel: t.params.resolveTargetBaseMipLevel, resolvePassAttachments.push({
baseArrayLayer: t.params.resolveTargetBaseArrayLayer, view: colorAttachment,
}), resolveTarget,
loadOp: 'load',
storeOp: t.params.storeOperation,
}); });
resolveTargets.push(resolveTarget);
} else { } else {
renderPassColorAttachments.push({ drawPassAttachments.push({
view: colorAttachment.createView(), view: colorAttachment,
resolveTarget,
clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }, clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 0.0 },
loadOp: 'clear', loadOp: 'clear',
storeOp: t.params.storeOperation, storeOp: t.params.storeOperation,
@@ -155,20 +163,22 @@ g.test('render_pass_resolve')
} }
const encoder = t.device.createCommandEncoder(); const encoder = t.device.createCommandEncoder();
const pass = encoder.beginRenderPass({ colorAttachments: drawPassAttachments });
const pass = encoder.beginRenderPass({
colorAttachments: renderPassColorAttachments,
});
pass.setPipeline(pipeline); pass.setPipeline(pipeline);
pass.draw(3); pass.draw(3);
pass.end(); pass.end();
if (t.params.separateResolvePass) {
const pass = encoder.beginRenderPass({ colorAttachments: resolvePassAttachments });
pass.end();
}
t.device.queue.submit([encoder.finish()]); t.device.queue.submit([encoder.finish()]);
// Verify the resolve targets contain the correct values. Note that we use z to specify the // Verify the resolve targets contain the correct values. Note that we use z to specify the
// array layer from which to pull the pixels for testing. // array layer from which to pull the pixels for testing.
const z = t.params.resolveTargetBaseArrayLayer; const z = t.params.resolveTargetBaseArrayLayer;
for (const resolveTarget of resolveTargets) { for (const resolveTarget of resolveTargets) {
t.expectSinglePixelComparisonsAreOkInTexture( ttu.expectSinglePixelComparisonsAreOkInTexture(
t,
{ texture: resolveTarget, mipLevel: t.params.resolveTargetBaseMipLevel }, { texture: resolveTarget, mipLevel: t.params.resolveTargetBaseMipLevel },
[ [
// Top left pixel should be {1.0, 1.0, 1.0, 1.0}. // Top left pixel should be {1.0, 1.0, 1.0, 1.0}.

View File

@@ -28,14 +28,22 @@ export const description = `API Operation Tests for RenderPass StoreOp.
TODO: test with more interesting loadOp values`; TODO: test with more interesting loadOp values`;
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { assert } from '../../../../common/util/util.js';
import { import {
EncodableTextureFormat,
isDepthTextureFormat, isDepthTextureFormat,
isSintOrUintFormat,
isStencilTextureFormat, isStencilTextureFormat,
kPossibleColorRenderableTextureFormats, kPossibleColorRenderableTextureFormats,
kSizedDepthStencilFormats, kSizedDepthStencilFormats,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import { PerTexelComponent } from '../../../util/texture/texel_data.js'; import * as ttu from '../../../texture_test_utils.js';
import {
kTexelRepresentationInfo,
PerTexelComponent,
TexelComponent,
} from '../../../util/texture/texel_data.js';
// Test with a zero and non-zero mip. // Test with a zero and non-zero mip.
const kMipLevel: number[] = [0, 1]; const kMipLevel: number[] = [0, 1];
@@ -150,35 +158,66 @@ g.test('render_pass_store_op,color_attachment_only')
.combine('arrayLayer', kArrayLayers) .combine('arrayLayer', kArrayLayers)
) )
.fn(t => { .fn(t => {
t.skipIfTextureFormatNotSupported(t.params.colorFormat); const { colorFormat, storeOperation, mipLevel, arrayLayer } = t.params;
t.skipIfTextureFormatNotUsableAsRenderAttachment(t.params.colorFormat); t.skipIfTextureFormatNotSupported(colorFormat);
t.skipIfTextureFormatNotUsableAsRenderAttachment(colorFormat);
const colorAttachment = t.createTextureTracked({ const colorAttachment = t.createTextureTracked({
format: t.params.colorFormat, format: colorFormat,
size: { width: kWidth, height: kHeight, depthOrArrayLayers: t.params.arrayLayer + 1 }, size: { width: kWidth, height: kHeight, depthOrArrayLayers: arrayLayer + 1 },
mipLevelCount: kMipLevelCount, mipLevelCount: kMipLevelCount,
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT, usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
}); });
const colorViewDesc: GPUTextureViewDescriptor = { const colorViewDesc: GPUTextureViewDescriptor = {
baseArrayLayer: t.params.arrayLayer, baseArrayLayer: arrayLayer,
baseMipLevel: t.params.mipLevel, baseMipLevel: mipLevel,
mipLevelCount: 1, mipLevelCount: 1,
arrayLayerCount: 1, arrayLayerCount: 1,
}; };
const colorAttachmentView = colorAttachment.createView(colorViewDesc); const colorAttachmentView = colorAttachment.createView(colorViewDesc);
// Color load operation will clear to {1.0, 0.0, 0.0, 1.0}. const components = new Set(
kTexelRepresentationInfo[colorFormat as EncodableTextureFormat]?.componentOrder ?? []
);
assert(components.size > 0);
// Note: for unorm/float values we specifically want values
// that will generate failure if srgb remapping is applied so
// we can't choose 0 or 1 for R, G, or B
const missingValue = { R: 0, G: 0, B: 0, A: 1 };
const [baseValue, maxDiff] = isSintOrUintFormat(colorFormat)
? [{ R: 12, G: 34, B: 56, A: 3 }, 0]
: [{ R: 0.8, G: 0.75, B: 0.5, A: 1.0 }, 2 / 255];
const kRGBAComponents = [
TexelComponent.R,
TexelComponent.G,
TexelComponent.B,
TexelComponent.A,
] as const;
const clearValueAsComponents = Object.fromEntries(
kRGBAComponents.map(component => [
component,
components.has(component) ? baseValue[component] : missingValue[component],
])
);
const clearValue = Object.fromEntries(
Object.entries(clearValueAsComponents).map(([k, v]) => [k.toLowerCase(), v])
) as unknown as GPUColorDict;
t.debug(`clearValue: ${JSON.stringify(clearValue)}`);
// Color store operation is determined by the test params. // Color store operation is determined by the test params.
const encoder = t.device.createCommandEncoder(); const encoder = t.device.createCommandEncoder();
const pass = encoder.beginRenderPass({ const pass = encoder.beginRenderPass({
colorAttachments: [ colorAttachments: [
{ {
view: colorAttachmentView, view: colorAttachmentView,
clearValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, clearValue,
loadOp: 'clear', loadOp: 'clear',
storeOp: t.params.storeOperation, storeOp: storeOperation,
}, },
], ],
}); });
@@ -187,19 +226,20 @@ g.test('render_pass_store_op,color_attachment_only')
// Check that the correct store operation occurred. // Check that the correct store operation occurred.
let expectedValue: PerTexelComponent<number> = {}; let expectedValue: PerTexelComponent<number> = {};
if (t.params.storeOperation === 'discard') { if (storeOperation === 'discard') {
// If colorStoreOp was clear, the texture should now contain {0.0, 0.0, 0.0, 0.0}. // If colorStoreOp was clear, the texture should now contain {0.0, 0.0, 0.0, 0.0}.
expectedValue = { R: 0.0, G: 0.0, B: 0.0, A: 0.0 }; expectedValue = { R: 0.0, G: 0.0, B: 0.0, A: 0.0 };
} else if (t.params.storeOperation === 'store') { } else if (storeOperation === 'store') {
// If colorStoreOP was store, the texture should still contain {1.0, 0.0, 0.0, 1.0}. // If colorStoreOP was store, the texture should still contain
expectedValue = { R: 1.0, G: 0.0, B: 0.0, A: 1.0 }; expectedValue = clearValueAsComponents;
} }
t.expectSingleColor(colorAttachment, t.params.colorFormat, { ttu.expectSingleColorWithTolerance(t, colorAttachment, colorFormat, {
size: [kHeight, kWidth, 1], size: [kHeight, kWidth, 1],
slice: t.params.arrayLayer, slice: arrayLayer,
exp: expectedValue, exp: expectedValue,
layout: { mipLevel: t.params.mipLevel }, layout: { mipLevel },
maxFractionalDiff: maxDiff,
}); });
}); });

View File

@@ -6,7 +6,8 @@ Test all culling combinations of GPUFrontFace and GPUCullMode show the correct o
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { isStencilTextureFormat, SizedTextureFormat } from '../../../format_info.js'; import { isStencilTextureFormat, SizedTextureFormat } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
function faceIsCulled(face: 'cw' | 'ccw', frontFace: GPUFrontFace, cullMode: GPUCullMode): boolean { function faceIsCulled(face: 'cw' | 'ccw', frontFace: GPUFrontFace, cullMode: GPUCullMode): boolean {
return cullMode !== 'none' && (frontFace === face) === (cullMode === 'front'); return cullMode !== 'none' && (frontFace === face) === (cullMode === 'front');
@@ -24,13 +25,13 @@ function faceColor(face: 'cw' | 'ccw', frontFace: GPUFrontFace, cullMode: GPUCul
} }
} }
class CullingTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) { class CullingTest extends AllFeaturesMaxLimitsGPUTest {
checkCornerPixels( checkCornerPixels(
texture: GPUTexture, texture: GPUTexture,
expectedTopLeftColor: Uint8Array, expectedTopLeftColor: Uint8Array,
expectedBottomRightColor: Uint8Array expectedBottomRightColor: Uint8Array
) { ) {
this.expectSinglePixelComparisonsAreOkInTexture({ texture }, [ ttu.expectSinglePixelComparisonsAreOkInTexture(this, { texture }, [
{ coord: { x: 0, y: 0 }, exp: expectedTopLeftColor }, { coord: { x: 0, y: 0 }, exp: expectedTopLeftColor },
{ coord: { x: texture.width - 1, y: texture.height - 1 }, exp: expectedBottomRightColor }, { coord: { x: texture.width - 1, y: texture.height - 1 }, exp: expectedBottomRightColor },
]); ]);

View File

@@ -11,7 +11,8 @@ import {
isSintOrUintFormat, isSintOrUintFormat,
kPossibleColorRenderableTextureFormats, kPossibleColorRenderableTextureFormats,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { getFragmentShaderCodeWithOutput, getPlainTypeInfo } from '../../../util/shader.js'; import { getFragmentShaderCodeWithOutput, getPlainTypeInfo } from '../../../util/shader.js';
import { kTexelRepresentationInfo } from '../../../util/texture/texel_data.js'; import { kTexelRepresentationInfo } from '../../../util/texture/texel_data.js';
@@ -27,7 +28,7 @@ const kVertexShader = `
} }
`; `;
export const g = makeTestGroup(TextureTestMixin(AllFeaturesMaxLimitsGPUTest)); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
// Values to write into each attachment // Values to write into each attachment
// We make values different for each attachment index and each channel // We make values different for each attachment index and each channel
@@ -139,7 +140,7 @@ g.test('color,attachments')
if (i === emptyAttachmentId) { if (i === emptyAttachmentId) {
continue; continue;
} }
t.expectSinglePixelComparisonsAreOkInTexture({ texture: renderTargets[i] }, [ ttu.expectSinglePixelComparisonsAreOkInTexture(t, { texture: renderTargets[i] }, [
{ coord: { x: 0, y: 0 }, exp: writeValues[i] }, { coord: { x: 0, y: 0 }, exp: writeValues[i] },
]); ]);
} }

View File

@@ -56,7 +56,8 @@ Test locations are framebuffer coordinates:
`; `;
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { PerPixelComparison } from '../../../util/texture/texture_ok.js'; import { PerPixelComparison } from '../../../util/texture/texture_ok.js';
const kRTSize: number = 56; const kRTSize: number = 56;
@@ -279,7 +280,7 @@ function generateVertexBuffer(vertexLocations: Point2D[]): Float32Array {
} }
const kDefaultDrawCount = 6; const kDefaultDrawCount = 6;
class PrimitiveTopologyTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) { class PrimitiveTopologyTest extends AllFeaturesMaxLimitsGPUTest {
makeAttachmentTexture(): GPUTexture { makeAttachmentTexture(): GPUTexture {
return this.createTextureTracked({ return this.createTextureTracked({
format: kColorFormat, format: kColorFormat,
@@ -410,7 +411,11 @@ class PrimitiveTopologyTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest
renderPass.end(); renderPass.end();
this.device.queue.submit([encoder.finish()]); this.device.queue.submit([encoder.finish()]);
this.expectSinglePixelComparisonsAreOkInTexture({ texture: colorAttachment }, testLocations); ttu.expectSinglePixelComparisonsAreOkInTexture(
this,
{ texture: colorAttachment },
testLocations
);
} }
} }

View File

@@ -19,7 +19,8 @@ Details could be found at: https://github.com/gpuweb/cts/issues/2201
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { assert, range } from '../../../../common/util/util.js'; import { assert, range } from '../../../../common/util/util.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { checkElementsPassPredicate, checkElementsEqual } from '../../../util/check_contents.js'; import { checkElementsPassPredicate, checkElementsEqual } from '../../../util/check_contents.js';
import { Type } from '../../../util/conversion.js'; import { Type } from '../../../util/conversion.js';
import { TexelView } from '../../../util/texture/texel_view.js'; import { TexelView } from '../../../util/texture/texel_view.js';
@@ -263,7 +264,7 @@ struct FragmentOutput2 {
} }
`; `;
class F extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) { class F extends AllFeaturesMaxLimitsGPUTest {
private sampleTexture: GPUTexture | undefined; private sampleTexture: GPUTexture | undefined;
private sampler: GPUSampler | undefined; private sampler: GPUSampler | undefined;
@@ -278,7 +279,8 @@ class F extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
// texel 2 - Blue // texel 2 - Blue
// texel 3 - Yellow // texel 3 - Yellow
const kSampleTextureSize = 2; const kSampleTextureSize = 2;
this.sampleTexture = this.createTextureFromTexelView( this.sampleTexture = ttu.createTextureFromTexelView(
this,
TexelView.fromTexelsAsBytes(format, coord => { TexelView.fromTexelsAsBytes(format, coord => {
const id = coord.x + coord.y * kSampleTextureSize; const id = coord.x + coord.y * kSampleTextureSize;
return kColors[id]; return kColors[id];

View File

@@ -19,7 +19,8 @@ import {
EncodableTextureFormat, EncodableTextureFormat,
kPossibleColorRenderableTextureFormats, kPossibleColorRenderableTextureFormats,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { clamp } from '../../../util/math.js'; import { clamp } from '../../../util/math.js';
import { TexelView } from '../../../util/texture/texel_view.js'; import { TexelView } from '../../../util/texture/texel_view.js';
@@ -76,7 +77,7 @@ class BlendingTest extends AllFeaturesMaxLimitsGPUTest {
} }
} }
export const g = makeTestGroup(TextureTestMixin(BlendingTest)); export const g = makeTestGroup(BlendingTest);
function mapColor( function mapColor(
col: GPUColorDict, col: GPUColorDict,
@@ -367,7 +368,8 @@ struct FragOutput {
t.device.queue.submit([commandEncoder.finish()]); t.device.queue.submit([commandEncoder.finish()]);
t.expectSinglePixelComparisonsAreOkInTexture( ttu.expectSinglePixelComparisonsAreOkInTexture(
t,
{ texture: renderTarget }, { texture: renderTarget },
[ [
{ {
@@ -457,7 +459,12 @@ g.test('blending,formats')
format as EncodableTextureFormat, format as EncodableTextureFormat,
_coords => expColor _coords => expColor
); );
t.expectTexelViewComparisonIsOkInTexture({ texture: renderTarget }, expTexelView, [1, 1, 1]); ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: renderTarget },
expTexelView,
[1, 1, 1]
);
}); });
g.test('blend_constant,initial') g.test('blend_constant,initial')
@@ -505,7 +512,7 @@ g.test('blend_constant,initial')
// a white color buffer data. // a white color buffer data.
const expColor = { R: 0, G: 0, B: 0, A: 0 }; const expColor = { R: 0, G: 0, B: 0, A: 0 };
const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor); const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor);
t.expectTexelViewComparisonIsOkInTexture({ texture: renderTarget }, expTexelView, [ ttu.expectTexelViewComparisonIsOkInTexture(t, { texture: renderTarget }, expTexelView, [
kSize, kSize,
kSize, kSize,
]); ]);
@@ -564,7 +571,7 @@ g.test('blend_constant,setting')
const expColor = { R: r, G: g, B: b, A: a }; const expColor = { R: r, G: g, B: b, A: a };
const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor); const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor);
t.expectTexelViewComparisonIsOkInTexture({ texture: renderTarget }, expTexelView, [ ttu.expectTexelViewComparisonIsOkInTexture(t, { texture: renderTarget }, expTexelView, [
kSize, kSize,
kSize, kSize,
]); ]);
@@ -637,7 +644,7 @@ g.test('blend_constant,not_inherited')
const expColor = { R: 0, G: 0, B: 0, A: 0 }; const expColor = { R: 0, G: 0, B: 0, A: 0 };
const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor); const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor);
t.expectTexelViewComparisonIsOkInTexture({ texture: renderTarget }, expTexelView, [ ttu.expectTexelViewComparisonIsOkInTexture(t, { texture: renderTarget }, expTexelView, [
kSize, kSize,
kSize, kSize,
]); ]);
@@ -718,7 +725,7 @@ g.test('color_write_mask,channel_work')
const expColor = { R: r, G: g, B: b, A: a }; const expColor = { R: r, G: g, B: b, A: a };
const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor); const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor);
t.expectTexelViewComparisonIsOkInTexture({ texture: renderTarget }, expTexelView, [ ttu.expectTexelViewComparisonIsOkInTexture(t, { texture: renderTarget }, expTexelView, [
kSize, kSize,
kSize, kSize,
]); ]);
@@ -776,7 +783,7 @@ g.test('color_write_mask,blending_disabled')
const expColor = { R: 1, G: 0, B: 0, A: 0 }; const expColor = { R: 1, G: 0, B: 0, A: 0 };
const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor); const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor);
t.expectTexelViewComparisonIsOkInTexture({ texture: renderTarget }, expTexelView, [ ttu.expectTexelViewComparisonIsOkInTexture(t, { texture: renderTarget }, expTexelView, [
kSize, kSize,
kSize, kSize,
]); ]);
@@ -873,5 +880,10 @@ g.test('blending,clamping')
const expColor = { R: expValue, G: expValue, B: expValue, A: expValue }; const expColor = { R: expValue, G: expValue, B: expValue, A: expValue };
const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor); const expTexelView = TexelView.fromTexelsAsColors(format, _coords => expColor);
t.expectTexelViewComparisonIsOkInTexture({ texture: renderTarget }, expTexelView, [1, 1, 1]); ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: renderTarget },
expTexelView,
[1, 1, 1]
);
}); });

View File

@@ -5,7 +5,8 @@ Test related to depth buffer, depth op, compare func, etc.
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { TypedArrayBufferView } from '../../../../common/util/util.js'; import { TypedArrayBufferView } from '../../../../common/util/util.js';
import { isStencilTextureFormat, kDepthTextureFormats } from '../../../format_info.js'; import { isStencilTextureFormat, kDepthTextureFormats } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { TexelView } from '../../../util/texture/texel_view.js'; import { TexelView } from '../../../util/texture/texel_view.js';
const backgroundColor = [0x00, 0x00, 0x00, 0xff]; const backgroundColor = [0x00, 0x00, 0x00, 0xff];
@@ -21,7 +22,7 @@ type TestStates = {
depth: number; depth: number;
}; };
class DepthTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) { class DepthTest extends AllFeaturesMaxLimitsGPUTest {
runDepthStateTest(testStates: TestStates[], expectedColor: Float32Array) { runDepthStateTest(testStates: TestStates[], expectedColor: Float32Array) {
const renderTargetFormat = 'rgba8unorm'; const renderTargetFormat = 'rgba8unorm';
@@ -82,7 +83,12 @@ class DepthTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
}; };
const expTexelView = TexelView.fromTexelsAsColors(renderTargetFormat, _coords => expColor); const expTexelView = TexelView.fromTexelsAsColors(renderTargetFormat, _coords => expColor);
this.expectTexelViewComparisonIsOkInTexture({ texture: renderTarget }, expTexelView, [1, 1]); ttu.expectTexelViewComparisonIsOkInTexture(
this,
{ texture: renderTarget },
expTexelView,
[1, 1]
);
} }
createRenderPipelineForTest( createRenderPipelineForTest(
@@ -411,7 +417,7 @@ g.test('depth_compare_func')
pass.end(); pass.end();
t.device.queue.submit([encoder.finish()]); t.device.queue.submit([encoder.finish()]);
t.expectSinglePixelComparisonsAreOkInTexture({ texture: colorAttachment }, [ ttu.expectSinglePixelComparisonsAreOkInTexture(t, { texture: colorAttachment }, [
{ {
coord: { x: 0, y: 0 }, coord: { x: 0, y: 0 },
exp: new Uint8Array(_expected), exp: new Uint8Array(_expected),
@@ -519,7 +525,7 @@ g.test('reverse_depth')
pass.end(); pass.end();
t.device.queue.submit([encoder.finish()]); t.device.queue.submit([encoder.finish()]);
t.expectSinglePixelComparisonsAreOkInTexture({ texture: colorAttachment }, [ ttu.expectSinglePixelComparisonsAreOkInTexture(t, { texture: colorAttachment }, [
{ {
coord: { x: 0, y: 0 }, coord: { x: 0, y: 0 },
exp: new Uint8Array( exp: new Uint8Array(

View File

@@ -11,7 +11,8 @@ import {
isDepthTextureFormat, isDepthTextureFormat,
isStencilTextureFormat, isStencilTextureFormat,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { TexelView } from '../../../util/texture/texel_view.js'; import { TexelView } from '../../../util/texture/texel_view.js';
enum QuadAngle { enum QuadAngle {
@@ -30,7 +31,7 @@ enum QuadAngle {
// depthBias = 0.25 / (2 ** (-2 - 23)) = 8388608. // depthBias = 0.25 / (2 ** (-2 - 23)) = 8388608.
const kPointTwoFiveBiasForPointTwoFiveZOnFloat = 8388608; const kPointTwoFiveBiasForPointTwoFiveZOnFloat = 8388608;
class DepthBiasTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) { class DepthBiasTest extends AllFeaturesMaxLimitsGPUTest {
runDepthBiasTestInternal( runDepthBiasTestInternal(
depthFormat: DepthStencilFormat, depthFormat: DepthStencilFormat,
{ {
@@ -172,7 +173,12 @@ class DepthBiasTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
const expColor = { Depth: _expectedDepth }; const expColor = { Depth: _expectedDepth };
const expTexelView = TexelView.fromTexelsAsColors(depthFormat, _coords => expColor); const expTexelView = TexelView.fromTexelsAsColors(depthFormat, _coords => expColor);
this.expectTexelViewComparisonIsOkInTexture({ texture: depthTexture }, expTexelView, [1, 1]); ttu.expectTexelViewComparisonIsOkInTexture(
this,
{ texture: depthTexture },
expTexelView,
[1, 1]
);
} }
runDepthBiasTestFor24BitFormat( runDepthBiasTestFor24BitFormat(
@@ -207,7 +213,12 @@ class DepthBiasTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
A: _expectedColor[3], A: _expectedColor[3],
}; };
const expTexelView = TexelView.fromTexelsAsColors(renderTargetFormat, _coords => expColor); const expTexelView = TexelView.fromTexelsAsColors(renderTargetFormat, _coords => expColor);
this.expectTexelViewComparisonIsOkInTexture({ texture: renderTarget }, expTexelView, [1, 1]); ttu.expectTexelViewComparisonIsOkInTexture(
this,
{ texture: renderTarget },
expTexelView,
[1, 1]
);
} }
createRenderPipelineForTest( createRenderPipelineForTest(

View File

@@ -11,10 +11,11 @@ import {
TypedArrayBufferView, TypedArrayBufferView,
TypedArrayBufferViewConstructor, TypedArrayBufferViewConstructor,
} from '../../../../common/util/util.js'; } from '../../../../common/util/util.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { PerPixelComparison } from '../../../util/texture/texture_ok.js'; import { PerPixelComparison } from '../../../util/texture/texture_ok.js';
class DrawTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) { class DrawTest extends AllFeaturesMaxLimitsGPUTest {
checkTriangleDraw(opts: { checkTriangleDraw(opts: {
firstIndex: number | undefined; firstIndex: number | undefined;
count: number; count: number;
@@ -314,7 +315,11 @@ struct Output {
}); });
} }
} }
this.expectSinglePixelComparisonsAreOkInTexture({ texture: renderTarget }, pixelComparisons); ttu.expectSinglePixelComparisonsAreOkInTexture(
this,
{ texture: renderTarget },
pixelComparisons
);
} }
} }

View File

@@ -7,7 +7,8 @@ import {
kDrawIndirectParametersSize, kDrawIndirectParametersSize,
kDrawIndexedIndirectParametersSize, kDrawIndexedIndirectParametersSize,
} from '../../../capability_info.js'; } from '../../../capability_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
const filled = new Uint8Array([0, 255, 0, 255]); const filled = new Uint8Array([0, 255, 0, 255]);
const notFilled = new Uint8Array([0, 0, 0, 0]); const notFilled = new Uint8Array([0, 0, 0, 0]);
@@ -124,7 +125,7 @@ class F extends AllFeaturesMaxLimitsGPUTest {
} }
} }
export const g = makeTestGroup(TextureTestMixin(F)); export const g = makeTestGroup(F);
g.test('basics') g.test('basics')
.desc( .desc(
@@ -233,7 +234,7 @@ Params:
renderPass.end(); renderPass.end();
t.queue.submit([commandEncoder.finish()]); t.queue.submit([commandEncoder.finish()]);
t.expectSinglePixelComparisonsAreOkInTexture({ texture: renderTarget }, [ ttu.expectSinglePixelComparisonsAreOkInTexture(t, { texture: renderTarget }, [
// The bottom left area is filled // The bottom left area is filled
{ coord: { x: 0, y: 1 }, exp: filled }, { coord: { x: 0, y: 1 }, exp: filled },
// The top right area is not filled // The top right area is not filled

View File

@@ -16,7 +16,8 @@ import {
kDepthStencilFormats, kDepthStencilFormats,
depthStencilFormatAspectSize, depthStencilFormatAspectSize,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { align } from '../../../util/math.js'; import { align } from '../../../util/math.js';
import { DataArrayGenerator } from '../../../util/texture/data_generation.js'; import { DataArrayGenerator } from '../../../util/texture/data_generation.js';
import { dataBytesForCopyOrFail, getTextureCopyLayout } from '../../../util/texture/layout.js'; import { dataBytesForCopyOrFail, getTextureCopyLayout } from '../../../util/texture/layout.js';
@@ -32,7 +33,7 @@ type TestStates = {
stencil: number | undefined; stencil: number | undefined;
}; };
class StencilTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) { class StencilTest extends AllFeaturesMaxLimitsGPUTest {
checkStencilOperation( checkStencilOperation(
depthStencilFormat: DepthStencilFormat, depthStencilFormat: DepthStencilFormat,
testStencilState: GPUStencilFaceState, testStencilState: GPUStencilFaceState,
@@ -218,7 +219,12 @@ class StencilTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
A: expectedColor[3], A: expectedColor[3],
}; };
const expTexelView = TexelView.fromTexelsAsColors(renderTargetFormat, _coords => expColor); const expTexelView = TexelView.fromTexelsAsColors(renderTargetFormat, _coords => expColor);
this.expectTexelViewComparisonIsOkInTexture({ texture: renderTarget }, expTexelView, [1, 1]); ttu.expectTexelViewComparisonIsOkInTexture(
this,
{ texture: renderTarget },
expTexelView,
[1, 1]
);
} }
createRenderPipelineForTest(depthStencil: GPUDepthStencilState): GPURenderPipeline { createRenderPipelineForTest(depthStencil: GPUDepthStencilState): GPURenderPipeline {

View File

@@ -12,7 +12,8 @@ things. If there are no guarantees we can issue warnings instead of failures. Id
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { assert } from '../../../../common/util/util.js'; import { assert } from '../../../../common/util/util.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { checkElementsEqual } from '../../../util/check_contents.js'; import { checkElementsEqual } from '../../../util/check_contents.js';
import { TexelView } from '../../../util/texture/texel_view.js'; import { TexelView } from '../../../util/texture/texel_view.js';
import { PerPixelComparison } from '../../../util/texture/texture_ok.js'; import { PerPixelComparison } from '../../../util/texture/texture_ok.js';
@@ -161,7 +162,7 @@ class SamplerAnisotropicFilteringSlantedPlaneTest extends AllFeaturesMaxLimitsGP
} }
} }
export const g = makeTestGroup(TextureTestMixin(SamplerAnisotropicFilteringSlantedPlaneTest)); export const g = makeTestGroup(SamplerAnisotropicFilteringSlantedPlaneTest);
g.test('anisotropic_filter_checkerboard') g.test('anisotropic_filter_checkerboard')
.desc( .desc(
@@ -286,7 +287,8 @@ g.test('anisotropic_filter_mipmap_color')
}, },
]) ])
.fn(t => { .fn(t => {
const texture = t.createTextureFromTexelViewsMultipleMipmaps( const texture = ttu.createTextureFromTexelViewsMultipleMipmaps(
t,
colors.map(value => TexelView.fromTexelsAsBytes(kTextureFormat, _coords => value)), colors.map(value => TexelView.fromTexelsAsBytes(kTextureFormat, _coords => value)),
{ size: [4, 4, 1], usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING } { size: [4, 4, 1], usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING }
); );
@@ -321,5 +323,9 @@ g.test('anisotropic_filter_mipmap_color')
); );
} }
} }
t.expectSinglePixelComparisonsAreOkInTexture({ texture: colorAttachment }, pixelComparisons); ttu.expectSinglePixelComparisonsAreOkInTexture(
t,
{ texture: colorAttachment },
pixelComparisons
);
}); });

View File

@@ -14,7 +14,8 @@ import {
isTextureFormatColorRenderable, isTextureFormatColorRenderable,
kPossibleColorRenderableTextureFormats, kPossibleColorRenderableTextureFormats,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { getTextureCopyLayout } from '../../../util/texture/layout.js'; import { getTextureCopyLayout } from '../../../util/texture/layout.js';
import { TexelView } from '../../../util/texture/texel_view.js'; import { TexelView } from '../../../util/texture/texel_view.js';
@@ -38,7 +39,7 @@ const kPossiblyRenderablePossiblyFilterableColorTextureFormats =
getTextureFormatType(format) === 'unfilterable-float' getTextureFormatType(format) === 'unfilterable-float'
); );
class FilterModeTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) { class FilterModeTest extends AllFeaturesMaxLimitsGPUTest {
runFilterRenderPipeline( runFilterRenderPipeline(
sampler: GPUSampler, sampler: GPUSampler,
module: GPUShaderModule, module: GPUShaderModule,
@@ -53,7 +54,8 @@ class FilterModeTest extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
// to verify the result, which is always renderable. // to verify the result, which is always renderable.
renderTargetFormat = 'rgba32float'; renderTargetFormat = 'rgba32float';
} }
const sampleTexture = this.createTextureFromTexelView( const sampleTexture = ttu.createTextureFromTexelView(
this,
TexelView.fromTexelsAsColors(format, coord => { TexelView.fromTexelsAsColors(format, coord => {
const id = coord.x + coord.y * kCheckerTextureSize; const id = coord.x + coord.y * kCheckerTextureSize;
return kCheckerTextureData[id]; return kCheckerTextureData[id];
@@ -554,7 +556,8 @@ g.test('magFilter,nearest')
vertexCount, vertexCount,
instanceCount instanceCount
); );
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: render.texture }, { texture: render.texture },
expectedColors(render.format, 'nearest', addressModeU, addressModeV), expectedColors(render.format, 'nearest', addressModeU, addressModeV),
kNearestRenderDim kNearestRenderDim
@@ -669,7 +672,8 @@ g.test('magFilter,linear')
vertexCount, vertexCount,
instanceCount instanceCount
); );
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: render.texture }, { texture: render.texture },
expectedColors(render.format, 'linear', addressModeU, addressModeV), expectedColors(render.format, 'linear', addressModeU, addressModeV),
kLinearRenderDim kLinearRenderDim
@@ -796,7 +800,8 @@ g.test('minFilter,nearest')
vertexCount, vertexCount,
instanceCount instanceCount
); );
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: render.texture }, { texture: render.texture },
expectedColors(render.format, 'nearest', addressModeU, addressModeV), expectedColors(render.format, 'nearest', addressModeU, addressModeV),
kNearestRenderDim kNearestRenderDim
@@ -921,7 +926,8 @@ g.test('minFilter,linear')
vertexCount, vertexCount,
instanceCount instanceCount
); );
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: render.texture }, { texture: render.texture },
expectedColors(render.format, 'linear', addressModeU, addressModeV), expectedColors(render.format, 'linear', addressModeU, addressModeV),
kLinearRenderDim kLinearRenderDim
@@ -964,7 +970,8 @@ g.test('mipmapFilter')
const sampler = t.device.createSampler({ const sampler = t.device.createSampler({
mipmapFilter: filterMode, mipmapFilter: filterMode,
}); });
const sampleTexture = t.createTextureFromTexelViewsMultipleMipmaps( const sampleTexture = ttu.createTextureFromTexelViewsMultipleMipmaps(
t,
[ [
TexelView.fromTexelsAsColors(format, () => { TexelView.fromTexelsAsColors(format, () => {
return { R: 0.0, G: 0.0, B: 0.0, A: 1.0 }; return { R: 0.0, G: 0.0, B: 0.0, A: 1.0 };
@@ -1058,7 +1065,7 @@ g.test('mipmapFilter')
// Since mipmap filtering varies across different backends, we verify that the result exhibits // Since mipmap filtering varies across different backends, we verify that the result exhibits
// filtered characteristics without strict value equalities via copies to a buffer. // filtered characteristics without strict value equalities via copies to a buffer.
const buffer = t.copyWholeTextureToNewBufferSimple(renderTexture, 0); const buffer = ttu.copyWholeTextureToNewBufferSimple(t, renderTexture, 0);
t.expectGPUBufferValuesPassCheck( t.expectGPUBufferValuesPassCheck(
buffer, buffer,
actual => { actual => {

View File

@@ -7,10 +7,11 @@ Tests samplers with textures.
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { assert, range } from '../../../../common/util/util.js'; import { assert, range } from '../../../../common/util/util.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { TexelView } from '../../../util/texture/texel_view.js'; import { TexelView } from '../../../util/texture/texel_view.js';
export const g = makeTestGroup(TextureTestMixin(AllFeaturesMaxLimitsGPUTest)); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('sample_texture_combos') g.test('sample_texture_combos')
.desc( .desc(
@@ -333,7 +334,7 @@ ${declarationLines.join('\n')}
); );
const size = [numAcross, 2]; const size = [numAcross, 2];
t.expectTexelViewComparisonIsOkInTexture({ texture: renderTarget }, expTexelView, size); ttu.expectTexelViewComparisonIsOkInTexture(t, { texture: renderTarget }, expTexelView, size);
textures.forEach(texture => texture.destroy()); textures.forEach(texture => texture.destroy());
}); });

View File

@@ -11,10 +11,11 @@ import {
kDifferentBaseFormatRegularTextureFormats, kDifferentBaseFormatRegularTextureFormats,
RegularTextureFormat, RegularTextureFormat,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { TexelView } from '../../../util/texture/texel_view.js'; import { TexelView } from '../../../util/texture/texel_view.js';
export const g = makeTestGroup(TextureTestMixin(AllFeaturesMaxLimitsGPUTest)); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
const kColors = [ const kColors = [
{ R: 1.0, G: 0.0, B: 0.0, A: 0.8 }, { R: 1.0, G: 0.0, B: 0.0, A: 0.8 },
@@ -119,7 +120,7 @@ g.test('texture_binding')
const inputTexelView = makeInputTexelView(format); const inputTexelView = makeInputTexelView(format);
// Create the initial texture with the contents of the input texel view. // Create the initial texture with the contents of the input texel view.
const texture = t.createTextureFromTexelView(inputTexelView, { const texture = ttu.createTextureFromTexelView(t, inputTexelView, {
size: [kTextureSize, kTextureSize], size: [kTextureSize, kTextureSize],
usage: GPUTextureUsage.TEXTURE_BINDING, usage: GPUTextureUsage.TEXTURE_BINDING,
viewFormats: [viewFormat], viewFormats: [viewFormat],
@@ -181,7 +182,8 @@ g.test('texture_binding')
pass.end(); pass.end();
t.device.queue.submit([commandEncoder.finish()]); t.device.queue.submit([commandEncoder.finish()]);
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: outputTexture }, { texture: outputTexture },
TexelView.fromTexelsAsColors('rgba8unorm', reinterpretedTexelView.color, { TexelView.fromTexelsAsColors('rgba8unorm', reinterpretedTexelView.color, {
clampToFormatRange: true, clampToFormatRange: true,
@@ -245,7 +247,7 @@ in view format and match in base format.`
// Create the sample source with the contents of the input texel view. // Create the sample source with the contents of the input texel view.
// We will sample this texture into |renderTexture|. It uses the same format to keep the same // We will sample this texture into |renderTexture|. It uses the same format to keep the same
// number of bits of precision. // number of bits of precision.
const sampleSource = t.createTextureFromTexelView(inputTexelView, { const sampleSource = ttu.createTextureFromTexelView(t, inputTexelView, {
size: [kTextureSize, kTextureSize], size: [kTextureSize, kTextureSize],
usage: GPUTextureUsage.TEXTURE_BINDING, usage: GPUTextureUsage.TEXTURE_BINDING,
}); });
@@ -337,7 +339,8 @@ in view format and match in base format.`
const renderViewTexels = TexelView.fromTexelsAsColors(viewFormat, inputTexelView.color, { const renderViewTexels = TexelView.fromTexelsAsColors(viewFormat, inputTexelView.color, {
clampToFormatRange: true, clampToFormatRange: true,
}); });
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: singleSampleRenderTexture }, { texture: singleSampleRenderTexture },
renderViewTexels, renderViewTexels,
[kTextureSize, kTextureSize], [kTextureSize, kTextureSize],
@@ -349,7 +352,8 @@ in view format and match in base format.`
const resolveView = TexelView.fromTexelsAsColors(viewFormat, renderViewTexels.color, { const resolveView = TexelView.fromTexelsAsColors(viewFormat, renderViewTexels.color, {
clampToFormatRange: true, clampToFormatRange: true,
}); });
t.expectTexelViewComparisonIsOkInTexture( ttu.expectTexelViewComparisonIsOkInTexture(
t,
{ texture: resolveTexture }, { texture: resolveTexture },
resolveView, resolveView,
[kTextureSize, kTextureSize], [kTextureSize, kTextureSize],

View File

@@ -22,11 +22,12 @@ import {
kRegularTextureFormats, kRegularTextureFormats,
RegularTextureFormat, RegularTextureFormat,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest, GPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { AllFeaturesMaxLimitsGPUTest, GPUTest } from '../../../gpu_test.js';
import * as ttu from '../../../texture_test_utils.js';
import { kFullscreenQuadVertexShaderCode } from '../../../util/shader.js'; import { kFullscreenQuadVertexShaderCode } from '../../../util/shader.js';
import { TexelView } from '../../../util/texture/texel_view.js'; import { TexelView } from '../../../util/texture/texel_view.js';
export const g = makeTestGroup(TextureTestMixin(AllFeaturesMaxLimitsGPUTest)); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
const kTextureViewWriteMethods = [ const kTextureViewWriteMethods = [
'storage-write-fragment', 'storage-write-fragment',
@@ -388,7 +389,7 @@ TODO: Test rgb10a2uint when TexelRepresentation.numericRange is made per-compone
); );
// [1] Use copySinglePixelTextureToBufferUsingComputePass to check multisampled texture. // [1] Use copySinglePixelTextureToBufferUsingComputePass to check multisampled texture.
t.expectTexelViewComparisonIsOkInTexture({ texture }, expectedTexelView, [ ttu.expectTexelViewComparisonIsOkInTexture(t, { texture }, expectedTexelView, [
kTextureSize, kTextureSize,
kTextureSize, kTextureSize,
]); ]);

View File

@@ -1,5 +1,5 @@
export const description = ` export const description = `
Tests for GPUDevice.onuncapturederror. Tests for GPUDevice.onuncapturederror / addEventListener('uncapturederror')
`; `;
import { makeTestGroup } from '../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../common/framework/test_group.js';
@@ -12,12 +12,16 @@ g.test('iff_uncaptured')
.desc( .desc(
`{validation, out-of-memory} error should fire uncapturederror iff not captured by a scope.` `{validation, out-of-memory} error should fire uncapturederror iff not captured by a scope.`
) )
.params(u => u.combine('errorType', kGeneratableErrorScopeFilters)) .params(u =>
u
.combine('useOnuncapturederror', [false, true])
.combine('errorType', kGeneratableErrorScopeFilters)
)
.fn(async t => { .fn(async t => {
const { errorType } = t.params; const { useOnuncapturederror, errorType } = t.params;
const uncapturedErrorEvent = await t.expectUncapturedError(() => { const uncapturedErrorEvent = await t.expectUncapturedError(() => {
t.generateError(errorType); t.generateError(errorType);
}); }, useOnuncapturederror);
t.expect(t.isInstanceOfError(errorType, uncapturedErrorEvent.error)); t.expect(t.isInstanceOfError(errorType, uncapturedErrorEvent.error));
}); });

View File

@@ -10,10 +10,10 @@ import {
kBufferUsages, kBufferUsages,
} from '../../../capability_info.js'; } from '../../../capability_info.js';
import { GPUConst } from '../../../constants.js'; import { GPUConst } from '../../../constants.js';
import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import { kMaxSafeMultipleOf8 } from '../../../util/math.js'; import { kMaxSafeMultipleOf8 } from '../../../util/math.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
assert(kBufferSizeAlignment === 4); assert(kBufferSizeAlignment === 4);
g.test('size') g.test('size')
@@ -36,10 +36,9 @@ g.test('size')
const { mappedAtCreation, size } = t.params; const { mappedAtCreation, size } = t.params;
const isValid = !mappedAtCreation || size % kBufferSizeAlignment === 0; const isValid = !mappedAtCreation || size % kBufferSizeAlignment === 0;
const usage = BufferUsage.COPY_SRC; const usage = BufferUsage.COPY_SRC;
t.expectGPUError(
'validation', t.shouldThrow(isValid ? false : 'RangeError', () =>
() => t.createBufferTracked({ size, usage, mappedAtCreation }), t.createBufferTracked({ size, usage, mappedAtCreation })
!isValid
); );
}); });

View File

@@ -5,9 +5,10 @@ Validation tests for GPUBuffer.destroy.
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { kBufferUsages } from '../../../capability_info.js'; import { kBufferUsages } from '../../../capability_info.js';
import { GPUConst } from '../../../constants.js'; import { GPUConst } from '../../../constants.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as vtu from '../validation_test_utils.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('all_usages') g.test('all_usages')
.desc('Test destroying buffers of every usage type.') .desc('Test destroying buffers of every usage type.')
@@ -28,7 +29,7 @@ g.test('all_usages')
g.test('error_buffer') g.test('error_buffer')
.desc('Test that error buffers may be destroyed without generating validation errors.') .desc('Test that error buffers may be destroyed without generating validation errors.')
.fn(t => { .fn(t => {
const buf = t.getErrorBuffer(); const buf = vtu.getErrorBuffer(t);
buf.destroy(); buf.destroy();
}); });

View File

@@ -7,9 +7,10 @@ import { attemptGarbageCollection } from '../../../../common/util/collect_garbag
import { assert, unreachable } from '../../../../common/util/util.js'; import { assert, unreachable } from '../../../../common/util/util.js';
import { kBufferUsages } from '../../../capability_info.js'; import { kBufferUsages } from '../../../capability_info.js';
import { GPUConst } from '../../../constants.js'; import { GPUConst } from '../../../constants.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as vtu from '../validation_test_utils.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
async testMapAsyncCall( async testMapAsyncCall(
expectation: expectation:
| 'success' | 'success'
@@ -149,7 +150,7 @@ g.test('mapAsync,invalidBuffer')
.paramsSubcasesOnly(u => u.combine('mapMode', kMapModeOptions)) .paramsSubcasesOnly(u => u.combine('mapMode', kMapModeOptions))
.fn(async t => { .fn(async t => {
const { mapMode } = t.params; const { mapMode } = t.params;
const buffer = t.getErrorBuffer(); const buffer = vtu.getErrorBuffer(t);
await t.testMapAsyncCall( await t.testMapAsyncCall(
{ validationError: true, earlyRejection: false, rejectName: 'OperationError' }, { validationError: true, earlyRejection: false, rejectName: 'OperationError' },
buffer, buffer,

View File

@@ -9,6 +9,6 @@ TODO:
`; `;
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);

View File

@@ -3,9 +3,9 @@ Tests for capability checking for features enabling optional query types.
`; `;
import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { UniqueFeaturesAndLimitsValidationTest } from '../../validation_test.js'; import { UniqueFeaturesOrLimitsGPUTest } from '../../../../gpu_test.js';
export const g = makeTestGroup(UniqueFeaturesAndLimitsValidationTest); export const g = makeTestGroup(UniqueFeaturesOrLimitsGPUTest);
g.test('createQuerySet') g.test('createQuerySet')
.desc( .desc(

View File

@@ -7,16 +7,19 @@ import { getGPU } from '../../../../../common/util/navigator_gpu.js';
import { assert } from '../../../../../common/util/util.js'; import { assert } from '../../../../../common/util/util.js';
import { kCanvasTextureFormats } from '../../../../capability_info.js'; import { kCanvasTextureFormats } from '../../../../capability_info.js';
import { import {
kASTCCompressedTextureFormats,
kBCCompressedTextureFormats,
getBlockInfoForTextureFormat, getBlockInfoForTextureFormat,
isDepthOrStencilTextureFormat, isDepthOrStencilTextureFormat,
isTextureFormatPossiblyStorageReadable, isTextureFormatPossiblyStorageReadable,
isTextureFormatPossiblyUsableAsColorRenderAttachment, isTextureFormatPossiblyUsableAsColorRenderAttachment,
kOptionalTextureFormats, kOptionalTextureFormats,
} from '../../../../format_info.js'; } from '../../../../format_info.js';
import { UniqueFeaturesOrLimitsGPUTest } from '../../../../gpu_test.js';
import { kAllCanvasTypes, createCanvas } from '../../../../util/create_elements.js'; import { kAllCanvasTypes, createCanvas } from '../../../../util/create_elements.js';
import { UniqueFeaturesAndLimitsValidationTest } from '../../validation_test.js'; import * as vtu from '../../validation_test_utils.js';
export const g = makeTestGroup(UniqueFeaturesAndLimitsValidationTest); export const g = makeTestGroup(UniqueFeaturesOrLimitsGPUTest);
g.test('texture_descriptor') g.test('texture_descriptor')
.desc( .desc(
@@ -126,6 +129,94 @@ g.test('texture_view_descriptor')
}); });
}); });
g.test('texture_compression_bc_sliced_3d')
.desc(
`
Tests that creating a 3D texture with BC compressed format fails if the features don't contain
'texture-compression-bc' and 'texture-compression-bc-sliced-3d'.
`
)
.params(u =>
u
.combine('format', kBCCompressedTextureFormats)
.combine('supportsBC', [false, true])
.combine('supportsBCSliced3D', [false, true])
)
.beforeAllSubcases(t => {
const { supportsBC, supportsBCSliced3D } = t.params;
const requiredFeatures: GPUFeatureName[] = [];
if (supportsBC) {
requiredFeatures.push('texture-compression-bc');
}
if (supportsBCSliced3D) {
requiredFeatures.push('texture-compression-bc-sliced-3d');
}
t.selectDeviceOrSkipTestCase({ requiredFeatures });
})
.fn(t => {
const { format, supportsBC, supportsBCSliced3D } = t.params;
t.skipIfTextureFormatNotSupported(format);
const info = getBlockInfoForTextureFormat(format);
const descriptor: GPUTextureDescriptor = {
size: [info.blockWidth, info.blockHeight, 1],
dimension: '3d',
format,
usage: GPUTextureUsage.TEXTURE_BINDING,
};
t.expectValidationError(() => {
t.createTextureTracked(descriptor);
}, !supportsBC || !supportsBCSliced3D);
});
g.test('texture_compression_astc_sliced_3d')
.desc(
`
Tests that creating a 3D texture with ASTC compressed format fails if the features don't contain
'texture-compression-astc' and 'texture-compression-astc-sliced-3d'.
`
)
.params(u =>
u
.combine('format', kASTCCompressedTextureFormats)
.combine('supportsASTC', [false, true])
.combine('supportsASTCSliced3D', [false, true])
)
.beforeAllSubcases(t => {
const { supportsASTC, supportsASTCSliced3D } = t.params;
const requiredFeatures: GPUFeatureName[] = [];
if (supportsASTC) {
requiredFeatures.push('texture-compression-astc');
}
if (supportsASTCSliced3D) {
requiredFeatures.push('texture-compression-astc-sliced-3d');
}
t.selectDeviceOrSkipTestCase({ requiredFeatures });
})
.fn(t => {
const { format, supportsASTC, supportsASTCSliced3D } = t.params;
t.skipIfTextureFormatNotSupported(format);
const info = getBlockInfoForTextureFormat(format);
const descriptor: GPUTextureDescriptor = {
size: [info.blockWidth, info.blockHeight, 1],
dimension: '3d',
format,
usage: GPUTextureUsage.TEXTURE_BINDING,
};
t.expectValidationError(() => {
t.createTextureTracked(descriptor);
}, !supportsASTC || !supportsASTCSliced3D);
});
g.test('canvas_configuration') g.test('canvas_configuration')
.desc( .desc(
` `
@@ -289,7 +380,8 @@ g.test('color_target_state')
const { isAsync, format, enable_required_feature } = t.params; const { isAsync, format, enable_required_feature } = t.params;
t.skipIfTextureFormatNotUsableAsRenderAttachment(format); t.skipIfTextureFormatNotUsableAsRenderAttachment(format);
t.doCreateRenderPipelineTest( vtu.doCreateRenderPipelineTest(
t,
isAsync, isAsync,
enable_required_feature, enable_required_feature,
{ {
@@ -344,7 +436,8 @@ g.test('depth_stencil_state')
.fn(t => { .fn(t => {
const { isAsync, format, enable_required_feature } = t.params; const { isAsync, format, enable_required_feature } = t.params;
t.doCreateRenderPipelineTest( vtu.doCreateRenderPipelineTest(
t,
isAsync, isAsync,
enable_required_feature, enable_required_feature,
{ {
@@ -446,15 +539,28 @@ g.test('render_bundle_encoder_descriptor_depth_stencil_format')
g.test('check_capability_guarantees') g.test('check_capability_guarantees')
.desc( .desc(
`check "texture-compression-bc" is supported or both "texture-compression-etc2" and "texture-compression-astc" are supported.` `check any adapter returned by requestAdapter() must provide the following guarantees:
- "texture-compression-bc" is supported or both "texture-compression-etc2" and "texture-compression-astc" are supported
- either "texture-compression-bc" or "texture-compression-bc-sliced-3d" is supported, both must be supported.
`
) )
.fn(async t => { .fn(async t => {
const adapter = await getGPU(t.rec).requestAdapter(); const adapter = await getGPU(t.rec).requestAdapter();
assert(adapter !== null); assert(adapter !== null);
const features = adapter.features; const features = adapter.features;
const supportsBC = features.has('texture-compression-bc');
const supportsETC2ASTC =
features.has('texture-compression-etc2') && features.has('texture-compression-astc');
const supportsBCSliced3D = features.has('texture-compression-bc-sliced-3d');
t.expect(supportsBC || supportsETC2ASTC, 'Adapter must support BC or both ETC2 and ASTC');
if (supportsBC || supportsBCSliced3D) {
t.expect( t.expect(
features.has('texture-compression-bc') || supportsBC && supportsBCSliced3D,
(features.has('texture-compression-etc2') && features.has('texture-compression-astc')) 'If BC or BC Sliced 3D is supported, both must be'
); );
}
}); });

View File

@@ -4,6 +4,7 @@ createComputePipeline and createComputePipelineAsync validation tests.
Note: entry point matching tests are in shader_module/entry_point.spec.ts Note: entry point matching tests are in shader_module/entry_point.spec.ts
`; `;
import { AllFeaturesMaxLimitsGPUTest } from '../.././gpu_test.js';
import { makeTestGroup } from '../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../common/framework/test_group.js';
import { keysOf } from '../../../common/util/data_tables.js'; import { keysOf } from '../../../common/util/data_tables.js';
import { kValue } from '../../util/constants.js'; import { kValue } from '../../util/constants.js';
@@ -15,9 +16,9 @@ import {
getAPIBindGroupLayoutForResource, getAPIBindGroupLayoutForResource,
doResourcesMatch, doResourcesMatch,
} from './utils.js'; } from './utils.js';
import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js'; import * as vtu from './validation_test_utils.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
getShaderModule( getShaderModule(
shaderStage: TShaderStage = 'compute', shaderStage: TShaderStage = 'compute',
entryPoint: string = 'main' entryPoint: string = 'main'
@@ -40,7 +41,7 @@ Call the API with valid compute shader and matching valid entryPoint, making sur
.params(u => u.combine('isAsync', [true, false])) .params(u => u.combine('isAsync', [true, false]))
.fn(t => { .fn(t => {
const { isAsync } = t.params; const { isAsync } = t.params;
t.doCreateComputePipelineTest(isAsync, true, { vtu.doCreateComputePipelineTest(t, isAsync, true, {
layout: 'auto', layout: 'auto',
compute: { module: t.getShaderModule('compute', 'main'), entryPoint: 'main' }, compute: { module: t.getShaderModule('compute', 'main'), entryPoint: 'main' },
}); });
@@ -55,10 +56,10 @@ Tests calling createComputePipeline(Async) with a invalid compute shader, and ch
.params(u => u.combine('isAsync', [true, false])) .params(u => u.combine('isAsync', [true, false]))
.fn(t => { .fn(t => {
const { isAsync } = t.params; const { isAsync } = t.params;
t.doCreateComputePipelineTest(isAsync, false, { vtu.doCreateComputePipelineTest(t, isAsync, false, {
layout: 'auto', layout: 'auto',
compute: { compute: {
module: t.createInvalidShaderModule(), module: vtu.createInvalidShaderModule(t),
entryPoint: 'main', entryPoint: 'main',
}, },
}); });
@@ -85,7 +86,7 @@ and check that the APIs only accept compute shader.
entryPoint: 'main', entryPoint: 'main',
}, },
}; };
t.doCreateComputePipelineTest(isAsync, shaderModuleStage === 'compute', descriptor); vtu.doCreateComputePipelineTest(t, isAsync, shaderModuleStage === 'compute', descriptor);
}); });
g.test('shader_module,device_mismatch') g.test('shader_module,device_mismatch')
@@ -111,7 +112,7 @@ g.test('shader_module,device_mismatch')
}, },
}; };
t.doCreateComputePipelineTest(isAsync, !mismatched, descriptor); vtu.doCreateComputePipelineTest(t, isAsync, !mismatched, descriptor);
}); });
g.test('pipeline_layout,device_mismatch') g.test('pipeline_layout,device_mismatch')
@@ -134,7 +135,7 @@ g.test('pipeline_layout,device_mismatch')
}, },
}; };
t.doCreateComputePipelineTest(isAsync, !mismatched, descriptor); vtu.doCreateComputePipelineTest(t, isAsync, !mismatched, descriptor);
}); });
g.test('limits,workgroup_storage_size') g.test('limits,workgroup_storage_size')
@@ -172,7 +173,7 @@ Tests calling createComputePipeline(Async) validation for compute using <= devic
entryPoint: 'main', entryPoint: 'main',
}, },
}; };
t.doCreateComputePipelineTest(isAsync, count <= countAtLimit, descriptor); vtu.doCreateComputePipelineTest(t, isAsync, count <= countAtLimit, descriptor);
}); });
g.test('limits,invocations_per_workgroup') g.test('limits,invocations_per_workgroup')
@@ -210,7 +211,8 @@ Tests calling createComputePipeline(Async) validation for compute using <= devic
}, },
}; };
t.doCreateComputePipelineTest( vtu.doCreateComputePipelineTest(
t,
isAsync, isAsync,
size[0] * size[1] * size[2] <= t.device.limits.maxComputeInvocationsPerWorkgroup, size[0] * size[1] * size[2] <= t.device.limits.maxComputeInvocationsPerWorkgroup,
descriptor descriptor
@@ -262,7 +264,7 @@ Tests calling createComputePipeline(Async) validation for compute workgroup_size
workgroupX <= t.device.limits.maxComputeWorkgroupSizeX && workgroupX <= t.device.limits.maxComputeWorkgroupSizeX &&
workgroupY <= t.device.limits.maxComputeWorkgroupSizeY && workgroupY <= t.device.limits.maxComputeWorkgroupSizeY &&
workgroupZ <= t.device.limits.maxComputeWorkgroupSizeZ; workgroupZ <= t.device.limits.maxComputeWorkgroupSizeZ;
t.doCreateComputePipelineTest(isAsync, _success, descriptor); vtu.doCreateComputePipelineTest(t, isAsync, _success, descriptor);
}); });
g.test('overrides,identifier') g.test('overrides,identifier')
@@ -317,7 +319,7 @@ Tests calling createComputePipeline(Async) validation for overridable constants
}, },
}; };
t.doCreateComputePipelineTest(isAsync, _success, descriptor); vtu.doCreateComputePipelineTest(t, isAsync, _success, descriptor);
}); });
g.test('overrides,uninitialized') g.test('overrides,uninitialized')
@@ -375,7 +377,7 @@ Tests calling createComputePipeline(Async) validation for uninitialized overrida
}, },
}; };
t.doCreateComputePipelineTest(isAsync, _success, descriptor); vtu.doCreateComputePipelineTest(t, isAsync, _success, descriptor);
}); });
g.test('overrides,value,type_error') g.test('overrides,value,type_error')
@@ -412,7 +414,7 @@ Tests calling createComputePipeline(Async) validation for constant values like i
}, },
}; };
t.doCreateComputePipelineTest(isAsync, _success, descriptor, 'TypeError'); vtu.doCreateComputePipelineTest(t, isAsync, _success, descriptor, 'TypeError');
}); });
g.test('overrides,value,validation_error') g.test('overrides,value,validation_error')
@@ -473,7 +475,7 @@ TODO(#2060): test with last_castable_pipeline_override.
}, },
}; };
t.doCreateComputePipelineTest(isAsync, _success, descriptor); vtu.doCreateComputePipelineTest(t, isAsync, _success, descriptor);
}); });
g.test('overrides,entry_point,validation_error') g.test('overrides,entry_point,validation_error')
@@ -507,7 +509,7 @@ Tests that pipeline constant (override) errors only trigger on entry point usage
}, },
}; };
t.doCreateComputePipelineTest(isAsync, pipeEntryPoint === 'main_success', descriptor); vtu.doCreateComputePipelineTest(t, isAsync, pipeEntryPoint === 'main_success', descriptor);
}); });
g.test('overrides,value,validation_error,f16') g.test('overrides,value,validation_error,f16')
@@ -566,7 +568,7 @@ clarity on whether values like f16.positive.last_castable_pipeline_override woul
}, },
}; };
t.doCreateComputePipelineTest(isAsync, _success, descriptor); vtu.doCreateComputePipelineTest(t, isAsync, _success, descriptor);
}); });
const kOverridesWorkgroupSizeShaders = { const kOverridesWorkgroupSizeShaders = {
@@ -620,7 +622,7 @@ Tests calling createComputePipeline(Async) validation for overridable constants
}, },
}; };
t.doCreateComputePipelineTest(isAsync, _success, descriptor); vtu.doCreateComputePipelineTest(t, isAsync, _success, descriptor);
}); });
g.test('overrides,workgroup_size,limits') g.test('overrides,workgroup_size,limits')
@@ -655,7 +657,7 @@ Tests calling createComputePipeline(Async) validation for overridable constants
}, },
}; };
t.doCreateComputePipelineTest(isAsync, _success, descriptor); vtu.doCreateComputePipelineTest(t, isAsync, _success, descriptor);
}; };
testFn(limits.maxComputeWorkgroupSizeX, 1, 1, true); testFn(limits.maxComputeWorkgroupSizeX, 1, 1, true);
@@ -718,7 +720,7 @@ Tests calling createComputePipeline(Async) validation for overridable constants
}, },
}; };
t.doCreateComputePipelineTest(isAsync, _success, descriptor); vtu.doCreateComputePipelineTest(t, isAsync, _success, descriptor);
}; };
testFn(1, 1, true); testFn(1, 1, true);
@@ -763,7 +765,8 @@ g.test('resource_compatibility')
entryPoint: 'main', entryPoint: 'main',
}, },
}; };
t.doCreateComputePipelineTest( vtu.doCreateComputePipelineTest(
t,
t.params.isAsync, t.params.isAsync,
doResourcesMatch(apiResource, wgslResource), doResourcesMatch(apiResource, wgslResource),
descriptor descriptor

View File

@@ -4,6 +4,7 @@ export const description = `
TODO: Ensure sure tests cover all createBindGroup validation rules. TODO: Ensure sure tests cover all createBindGroup validation rules.
`; `;
import { AllFeaturesMaxLimitsGPUTest, kResourceStates } from '../.././gpu_test.js';
import { makeTestGroup } from '../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../common/framework/test_group.js';
import { assert, makeValueTestVariant, unreachable } from '../../../common/util/util.js'; import { assert, makeValueTestVariant, unreachable } from '../../../common/util/util.js';
import { import {
@@ -25,10 +26,9 @@ import {
} from '../../capability_info.js'; } from '../../capability_info.js';
import { GPUConst } from '../../constants.js'; import { GPUConst } from '../../constants.js';
import { kPossibleStorageTextureFormats, kRegularTextureFormats } from '../../format_info.js'; import { kPossibleStorageTextureFormats, kRegularTextureFormats } from '../../format_info.js';
import { kResourceStates } from '../../gpu_test.js';
import { getTextureDimensionFromView } from '../../util/texture/base.js'; import { getTextureDimensionFromView } from '../../util/texture/base.js';
import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js'; import * as vtu from './validation_test_utils.js';
const kTestFormat: GPUTextureFormat = 'r32float'; const kTestFormat: GPUTextureFormat = 'r32float';
@@ -37,7 +37,7 @@ function clone<T extends GPUTextureDescriptor>(descriptor: T): T {
} }
function skipIfResourceNotSupportedInStages( function skipIfResourceNotSupportedInStages(
t: AllFeaturesMaxLimitsValidationTest, t: AllFeaturesMaxLimitsGPUTest,
entry: BGLEntry, entry: BGLEntry,
visibility: number visibility: number
) { ) {
@@ -69,7 +69,7 @@ function skipIfResourceNotSupportedInStages(
} }
} }
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('binding_count_mismatch') g.test('binding_count_mismatch')
.desc('Test that the number of entries must match the number of entries in the BindGroupLayout.') .desc('Test that the number of entries must match the number of entries in the BindGroupLayout.')
@@ -95,7 +95,7 @@ g.test('binding_count_mismatch')
for (let i = 0; i < bindGroupEntryCount; ++i) { for (let i = 0; i < bindGroupEntryCount; ++i) {
entries.push({ entries.push({
binding: i, binding: i,
resource: { buffer: t.getStorageBuffer() }, resource: { buffer: vtu.getStorageBuffer(t) },
}); });
} }
@@ -127,7 +127,7 @@ g.test('binding_must_be_present_in_layout')
}); });
const descriptor = { const descriptor = {
entries: [{ binding, resource: { buffer: t.getStorageBuffer() } }], entries: [{ binding, resource: { buffer: vtu.getStorageBuffer(t) } }],
layout: bindGroupLayout, layout: bindGroupLayout,
}; };
@@ -154,7 +154,7 @@ g.test('binding_must_contain_resource_defined_in_layout')
entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, ...entry }], entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, ...entry }],
}); });
const resource = t.getBindingResource(resourceType); const resource = vtu.getBindingResource(t, resourceType);
const IsStorageTextureResourceType = (resourceType: BindableResource) => { const IsStorageTextureResourceType = (resourceType: BindableResource) => {
switch (resourceType) { switch (resourceType) {
@@ -581,7 +581,7 @@ g.test('buffer,resource_state')
], ],
}); });
const buffer = t.createBufferWithState(state, { const buffer = vtu.createBufferWithState(t, state, {
usage: info.usage, usage: info.usage,
size: 4, size: 4,
}); });
@@ -631,7 +631,7 @@ g.test('texture,resource_state')
? info.usage | GPUConst.TextureUsage.RENDER_ATTACHMENT ? info.usage | GPUConst.TextureUsage.RENDER_ATTACHMENT
: info.usage; : info.usage;
const format = entry.storageTexture !== undefined ? 'r32float' : 'rgba8unorm'; const format = entry.storageTexture !== undefined ? 'r32float' : 'rgba8unorm';
const texture = t.createTextureWithState(state, { const texture = vtu.createTextureWithState(t, state, {
usage, usage,
size: [1, 1], size: [1, 1],
format, format,
@@ -683,7 +683,7 @@ g.test('bind_group_layout,device_mismatch')
entries: [ entries: [
{ {
binding: 0, binding: 0,
resource: { buffer: t.getUniformBuffer() }, resource: { buffer: vtu.getUniformBuffer(t) },
}, },
], ],
}); });
@@ -728,11 +728,11 @@ g.test('binding_resources,device_mismatch')
skipIfResourceNotSupportedInStages(t, entry, visibility); skipIfResourceNotSupportedInStages(t, entry, visibility);
const resource0 = resource0Mismatched const resource0 = resource0Mismatched
? t.getDeviceMismatchedBindingResource(info.resource) ? vtu.getDeviceMismatchedBindingResource(t, info.resource)
: t.getBindingResource(info.resource); : vtu.getBindingResource(t, info.resource);
const resource1 = resource1Mismatched const resource1 = resource1Mismatched
? t.getDeviceMismatchedBindingResource(info.resource) ? vtu.getDeviceMismatchedBindingResource(t, info.resource)
: t.getBindingResource(info.resource); : vtu.getBindingResource(t, info.resource);
const bgl = t.device.createBindGroupLayout({ const bgl = t.device.createBindGroupLayout({
entries: [ entries: [

View File

@@ -4,6 +4,7 @@ createBindGroupLayout validation tests.
TODO: make sure tests are complete. TODO: make sure tests are complete.
`; `;
import { AllFeaturesMaxLimitsGPUTest } from '../.././gpu_test.js';
import { kUnitCaseParamsBuilder } from '../../../common/framework/params_builder.js'; import { kUnitCaseParamsBuilder } from '../../../common/framework/params_builder.js';
import { makeTestGroup } from '../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../common/framework/test_group.js';
import { import {
@@ -25,8 +26,6 @@ import {
kAllTextureFormats, kAllTextureFormats,
} from '../../format_info.js'; } from '../../format_info.js';
import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js';
function clone<T extends GPUBindGroupLayoutDescriptor>(descriptor: T): T { function clone<T extends GPUBindGroupLayoutDescriptor>(descriptor: T): T {
return JSON.parse(JSON.stringify(descriptor)); return JSON.parse(JSON.stringify(descriptor));
} }
@@ -77,7 +76,7 @@ function isValidBGLEntryForStages(device: GPUDevice, visibility: number, entry:
: true; : true;
} }
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('duplicate_bindings') g.test('duplicate_bindings')
.desc('Test that uniqueness of binding numbers across entries is enforced.') .desc('Test that uniqueness of binding numbers across entries is enforced.')

View File

@@ -4,6 +4,7 @@ createPipelineLayout validation tests.
TODO: review existing tests, write descriptions, and make sure tests are complete. TODO: review existing tests, write descriptions, and make sure tests are complete.
`; `;
import { AllFeaturesMaxLimitsGPUTest } from '../.././gpu_test.js';
import { makeTestGroup } from '../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../common/framework/test_group.js';
import { count } from '../../../common/util/util.js'; import { count } from '../../../common/util/util.js';
import { import {
@@ -13,13 +14,11 @@ import {
} from '../../capability_info.js'; } from '../../capability_info.js';
import { GPUConst } from '../../constants.js'; import { GPUConst } from '../../constants.js';
import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js';
function clone<T extends GPUBindGroupLayoutDescriptor>(descriptor: T): T { function clone<T extends GPUBindGroupLayoutDescriptor>(descriptor: T): T {
return JSON.parse(JSON.stringify(descriptor)); return JSON.parse(JSON.stringify(descriptor));
} }
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('number_of_dynamic_buffers_exceeds_the_maximum_value') g.test('number_of_dynamic_buffers_exceeds_the_maximum_value')
.desc( .desc(

View File

@@ -2,11 +2,10 @@ export const description = `
createSampler validation tests. createSampler validation tests.
`; `;
import { AllFeaturesMaxLimitsGPUTest } from '../.././gpu_test.js';
import { makeTestGroup } from '../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js'; export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest);
g.test('lodMinAndMaxClamp') g.test('lodMinAndMaxClamp')
.desc('test different combinations of min and max clamp values') .desc('test different combinations of min and max clamp values')

View File

@@ -1,5 +1,6 @@
export const description = `createTexture validation tests.`; export const description = `createTexture validation tests.`;
import { AllFeaturesMaxLimitsGPUTest } from '../.././gpu_test.js';
import { makeTestGroup } from '../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../common/framework/test_group.js';
import { assert, makeValueTestVariant } from '../../../common/util/util.js'; import { assert, makeValueTestVariant } from '../../../common/util/util.js';
import { kTextureDimensions, kTextureUsages } from '../../capability_info.js'; import { kTextureDimensions, kTextureUsages } from '../../capability_info.js';
@@ -20,12 +21,11 @@ import {
isTextureFormatPossiblyStorageReadable, isTextureFormatPossiblyStorageReadable,
isColorTextureFormat, isColorTextureFormat,
textureFormatsAreViewCompatible, textureFormatsAreViewCompatible,
textureDimensionAndFormatCompatibleForDevice,
} from '../../format_info.js'; } from '../../format_info.js';
import { maxMipLevelCount } from '../../util/texture/base.js'; import { maxMipLevelCount } from '../../util/texture/base.js';
import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js'; export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest);
g.test('zero_size_and_usage') g.test('zero_size_and_usage')
.desc( .desc(
@@ -101,7 +101,8 @@ g.test('zero_size_and_usage')
g.test('dimension_type_and_format_compatibility') g.test('dimension_type_and_format_compatibility')
.desc( .desc(
`Test every dimension type on every format. Note that compressed formats and depth/stencil formats are not valid for 1D/3D dimension types.` `Test every dimension type on every format. Note that compressed formats and depth/stencil formats are not valid
for 1D dimension types while it depends on the format for 3D types.`
) )
.params(u => .params(u =>
u // u //
@@ -120,9 +121,12 @@ g.test('dimension_type_and_format_compatibility')
usage: GPUTextureUsage.TEXTURE_BINDING, usage: GPUTextureUsage.TEXTURE_BINDING,
}; };
t.expectValidationError(() => { t.expectValidationError(
() => {
t.createTextureTracked(descriptor); t.createTextureTracked(descriptor);
}, !textureDimensionAndFormatCompatible(dimension, format)); },
!textureDimensionAndFormatCompatibleForDevice(t.device, dimension, format)
);
}); });
g.test('mipLevelCount,format') g.test('mipLevelCount,format')

View File

@@ -1,5 +1,6 @@
export const description = `createView validation tests.`; export const description = `createView validation tests.`;
import { AllFeaturesMaxLimitsGPUTest, kResourceStates } from '../.././gpu_test.js';
import { kUnitCaseParamsBuilder } from '../../../common/framework/params_builder.js'; import { kUnitCaseParamsBuilder } from '../../../common/framework/params_builder.js';
import { makeTestGroup } from '../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../common/framework/test_group.js';
import { unreachable } from '../../../common/util/util.js'; import { unreachable } from '../../../common/util/util.js';
@@ -20,7 +21,6 @@ import {
getBlockInfoForTextureFormat, getBlockInfoForTextureFormat,
isTextureFormatPossiblyUsableAsRenderAttachment, isTextureFormatPossiblyUsableAsRenderAttachment,
} from '../../format_info.js'; } from '../../format_info.js';
import { kResourceStates } from '../../gpu_test.js';
import { import {
getTextureDimensionFromView, getTextureDimensionFromView,
reifyTextureViewDescriptor, reifyTextureViewDescriptor,
@@ -28,9 +28,9 @@ import {
} from '../../util/texture/base.js'; } from '../../util/texture/base.js';
import { reifyExtent3D } from '../../util/unions.js'; import { reifyExtent3D } from '../../util/unions.js';
import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js'; import * as vtu from './validation_test_utils.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
const kLevels = 6; const kLevels = 6;
@@ -331,7 +331,7 @@ g.test('texture_state')
.paramsSubcasesOnly(u => u.combine('state', kResourceStates)) .paramsSubcasesOnly(u => u.combine('state', kResourceStates))
.fn(t => { .fn(t => {
const { state } = t.params; const { state } = t.params;
const texture = t.createTextureWithState(state); const texture = vtu.createTextureWithState(t, state);
t.expectValidationError(() => { t.expectValidationError(() => {
texture.createView(); texture.createView();

View File

@@ -2,11 +2,10 @@ export const description = `
Test validation of pushDebugGroup, popDebugGroup, and insertDebugMarker. Test validation of pushDebugGroup, popDebugGroup, and insertDebugMarker.
`; `;
import { AllFeaturesMaxLimitsGPUTest } from '../.././gpu_test.js';
import { makeTestGroup } from '../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js'; class F extends AllFeaturesMaxLimitsGPUTest {
class F extends AllFeaturesMaxLimitsValidationTest {
beginRenderPass(commandEncoder: GPUCommandEncoder): GPURenderPassEncoder { beginRenderPass(commandEncoder: GPUCommandEncoder): GPURenderPassEncoder {
const attachmentTexture = this.createTextureTracked({ const attachmentTexture = this.createTextureTracked({
format: 'rgba8unorm', format: 'rgba8unorm',

View File

@@ -4,9 +4,10 @@ Tests for validation in beginComputePass and GPUComputePassDescriptor as its opt
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { kQueryTypes } from '../../../capability_info.js'; import { kQueryTypes } from '../../../capability_info.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as vtu from '../validation_test_utils.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
tryComputePass(success: boolean, descriptor: GPUComputePassDescriptor): void { tryComputePass(success: boolean, descriptor: GPUComputePassDescriptor): void {
const encoder = this.device.createCommandEncoder(); const encoder = this.device.createCommandEncoder();
const computePass = encoder.beginComputePass(descriptor); const computePass = encoder.beginComputePass(descriptor);
@@ -57,7 +58,7 @@ g.test('timestampWrites,invalid_query_set')
t.skipIfDeviceDoesNotSupportQueryType('timestamp'); t.skipIfDeviceDoesNotSupportQueryType('timestamp');
const { querySetState } = t.params; const { querySetState } = t.params;
const querySet = t.createQuerySetWithState(querySetState, { const querySet = vtu.createQuerySetWithState(t, querySetState, {
type: 'timestamp', type: 'timestamp',
count: 1, count: 1,
}); });

View File

@@ -22,9 +22,10 @@ Notes:
`; `;
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as vtu from '../validation_test_utils.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('color_attachments,device_mismatch') g.test('color_attachments,device_mismatch')
.desc( .desc(
@@ -68,17 +69,17 @@ g.test('color_attachments,device_mismatch')
const mismatched = view0Mismatched || target0Mismatched || view1Mismatched || target1Mismatched; const mismatched = view0Mismatched || target0Mismatched || view1Mismatched || target1Mismatched;
const view0Texture = view0Mismatched const view0Texture = view0Mismatched
? t.getDeviceMismatchedRenderTexture(4) ? vtu.getDeviceMismatchedRenderTexture(t, 4)
: t.getRenderTexture(4); : vtu.getRenderTexture(t, 4);
const target0Texture = target0Mismatched const target0Texture = target0Mismatched
? t.getDeviceMismatchedRenderTexture() ? vtu.getDeviceMismatchedRenderTexture(t)
: t.getRenderTexture(); : vtu.getRenderTexture(t);
const view1Texture = view1Mismatched const view1Texture = view1Mismatched
? t.getDeviceMismatchedRenderTexture(4) ? vtu.getDeviceMismatchedRenderTexture(t, 4)
: t.getRenderTexture(4); : vtu.getRenderTexture(t, 4);
const target1Texture = target1Mismatched const target1Texture = target1Mismatched
? t.getDeviceMismatchedRenderTexture() ? vtu.getDeviceMismatchedRenderTexture(t)
: t.getRenderTexture(); : vtu.getRenderTexture(t);
const encoder = t.createEncoder('non-pass'); const encoder = t.createEncoder('non-pass');
const pass = encoder.encoder.beginRenderPass({ const pass = encoder.encoder.beginRenderPass({
@@ -120,7 +121,7 @@ g.test('depth_stencil_attachment,device_mismatch')
}; };
const depthStencilTexture = mismatched const depthStencilTexture = mismatched
? t.getDeviceMismatchedTexture(descriptor) ? vtu.getDeviceMismatchedTexture(t, descriptor)
: t.createTextureTracked(descriptor); : t.createTextureTracked(descriptor);
const encoder = t.createEncoder('non-pass'); const encoder = t.createEncoder('non-pass');

View File

@@ -4,11 +4,11 @@ API validation tests for clearBuffer.
import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { kBufferUsages } from '../../../../capability_info.js'; import { kBufferUsages } from '../../../../capability_info.js';
import { kResourceStates } from '../../../../gpu_test.js'; import { kResourceStates, AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js';
import { kMaxSafeMultipleOf8 } from '../../../../util/math.js'; import { kMaxSafeMultipleOf8 } from '../../../../util/math.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; import * as vtu from '../../validation_test_utils.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
TestClearBuffer(options: { TestClearBuffer(options: {
buffer: GPUBuffer; buffer: GPUBuffer;
offset: number | undefined; offset: number | undefined;
@@ -34,7 +34,7 @@ g.test('buffer_state')
.fn(t => { .fn(t => {
const { bufferState } = t.params; const { bufferState } = t.params;
const buffer = t.createBufferWithState(bufferState, { const buffer = vtu.createBufferWithState(t, bufferState, {
size: 8, size: 8,
usage: GPUBufferUsage.COPY_DST, usage: GPUBufferUsage.COPY_DST,
}); });

View File

@@ -8,16 +8,20 @@ import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { makeValueTestVariant } from '../../../../../common/util/util.js'; import { makeValueTestVariant } from '../../../../../common/util/util.js';
import { kBufferUsages } from '../../../../capability_info.js'; import { kBufferUsages } from '../../../../capability_info.js';
import { GPUConst } from '../../../../constants.js'; import { GPUConst } from '../../../../constants.js';
import { kResourceStates, ResourceState } from '../../../../gpu_test.js'; import {
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; kResourceStates,
ResourceState,
AllFeaturesMaxLimitsGPUTest,
} from '../../../../gpu_test.js';
import * as vtu from '../../validation_test_utils.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
createComputePipeline(state: 'valid' | 'invalid'): GPUComputePipeline { createComputePipeline(state: 'valid' | 'invalid'): GPUComputePipeline {
if (state === 'valid') { if (state === 'valid') {
return this.createNoOpComputePipeline(); return vtu.createNoOpComputePipeline(this);
} }
return this.createErrorComputePipeline(); return vtu.createErrorComputePipeline(this);
} }
createIndirectBuffer(state: ResourceState, data: Uint32Array): GPUBuffer { createIndirectBuffer(state: ResourceState, data: Uint32Array): GPUBuffer {
@@ -119,7 +123,7 @@ g.test('dispatch_sizes')
const maxDispatch = t.device.limits.maxComputeWorkgroupsPerDimension; const maxDispatch = t.device.limits.maxComputeWorkgroupsPerDimension;
const largeDimValue = makeValueTestVariant(maxDispatch, largeDimValueVariant); const largeDimValue = makeValueTestVariant(maxDispatch, largeDimValueVariant);
const pipeline = t.createNoOpComputePipeline(); const pipeline = vtu.createNoOpComputePipeline(t);
const workSizes = [smallDimValue, smallDimValue, smallDimValue]; const workSizes = [smallDimValue, smallDimValue, smallDimValue];
workSizes[largeDimIndex] = largeDimValue; workSizes[largeDimIndex] = largeDimValue;
@@ -172,7 +176,7 @@ and an indirectBuffer with 6 elements.
) )
.fn(t => { .fn(t => {
const { state, offset } = t.params; const { state, offset } = t.params;
const pipeline = t.createNoOpComputePipeline(); const pipeline = vtu.createNoOpComputePipeline(t);
const buffer = t.createIndirectBuffer(state, kBufferData); const buffer = t.createIndirectBuffer(state, kBufferData);
const { encoder, validateFinishAndSubmit } = t.createEncoder('compute pass'); const { encoder, validateFinishAndSubmit } = t.createEncoder('compute pass');
@@ -195,7 +199,7 @@ g.test('indirect_dispatch_buffer,device_mismatch')
.fn(t => { .fn(t => {
const { mismatched } = t.params; const { mismatched } = t.params;
const pipeline = t.createNoOpComputePipeline(); const pipeline = vtu.createNoOpComputePipeline(t);
const sourceDevice = mismatched ? t.mismatchedDevice : t.device; const sourceDevice = mismatched ? t.mismatchedDevice : t.device;
@@ -238,7 +242,7 @@ g.test('indirect_dispatch_buffer,usage')
const bufferUsage = bufferUsage0 | bufferUsage1; const bufferUsage = bufferUsage0 | bufferUsage1;
const layout = t.device.createPipelineLayout({ bindGroupLayouts: [] }); const layout = t.device.createPipelineLayout({ bindGroupLayouts: [] });
const pipeline = t.createNoOpComputePipeline(layout); const pipeline = vtu.createNoOpComputePipeline(t, layout);
const buffer = t.createBufferTracked({ const buffer = t.createBufferTracked({
size: 16, size: 16,

View File

@@ -25,11 +25,11 @@ Test Plan:
import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { kBufferUsages } from '../../../../capability_info.js'; import { kBufferUsages } from '../../../../capability_info.js';
import { kResourceStates } from '../../../../gpu_test.js'; import { kResourceStates, AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js';
import { kMaxSafeMultipleOf8 } from '../../../../util/math.js'; import { kMaxSafeMultipleOf8 } from '../../../../util/math.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; import * as vtu from '../../validation_test_utils.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
TestCopyBufferToBuffer(options: { TestCopyBufferToBuffer(options: {
srcBuffer: GPUBuffer; srcBuffer: GPUBuffer;
srcOffset: number; srcOffset: number;
@@ -66,11 +66,11 @@ g.test('buffer_state')
) )
.fn(t => { .fn(t => {
const { srcBufferState, dstBufferState } = t.params; const { srcBufferState, dstBufferState } = t.params;
const srcBuffer = t.createBufferWithState(srcBufferState, { const srcBuffer = vtu.createBufferWithState(t, srcBufferState, {
size: 16, size: 16,
usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
}); });
const dstBuffer = t.createBufferWithState(dstBufferState, { const dstBuffer = vtu.createBufferWithState(t, dstBufferState, {
size: 16, size: 16,
usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
}); });

View File

@@ -15,11 +15,11 @@ import {
canCopyToAllAspectsOfTextureFormat, canCopyToAllAspectsOfTextureFormat,
ColorTextureFormat, ColorTextureFormat,
} from '../../../../format_info.js'; } from '../../../../format_info.js';
import { kResourceStates } from '../../../../gpu_test.js'; import { kResourceStates, AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js';
import { align, lcm } from '../../../../util/math.js'; import { align, lcm } from '../../../../util/math.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; import * as vtu from '../../validation_test_utils.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
TestCopyTextureToTexture( TestCopyTextureToTexture(
source: GPUTexelCopyTextureInfo, source: GPUTexelCopyTextureInfo,
destination: GPUTexelCopyTextureInfo, destination: GPUTexelCopyTextureInfo,
@@ -90,8 +90,8 @@ g.test('copy_with_invalid_or_destroyed_texture')
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST, usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
}; };
const srcTexture = t.createTextureWithState(srcState, textureDesc); const srcTexture = vtu.createTextureWithState(t, srcState, textureDesc);
const dstTexture = t.createTextureWithState(dstState, textureDesc); const dstTexture = vtu.createTextureWithState(t, dstState, textureDesc);
const isSubmitSuccess = srcState === 'valid' && dstState === 'valid'; const isSubmitSuccess = srcState === 'valid' && dstState === 'valid';
const isFinishSuccess = srcState !== 'invalid' && dstState !== 'invalid'; const isFinishSuccess = srcState !== 'invalid' && dstState !== 'invalid';

View File

@@ -14,10 +14,10 @@ Test Coverage:
`; `;
import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js';
import { kEncoderTypes } from '../../../../util/command_buffer_maker.js'; import { kEncoderTypes } from '../../../../util/command_buffer_maker.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('debug_group_balanced') g.test('debug_group_balanced')
.params(u => .params(u =>

View File

@@ -3,9 +3,9 @@ Validation tests for indexed draws accessing the index buffer.
`; `;
import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
createIndexBuffer(indexData: Iterable<number>): GPUBuffer { createIndexBuffer(indexData: Iterable<number>): GPUBuffer {
return this.makeBufferWithContents(new Uint32Array(indexData), GPUBufferUsage.INDEX); return this.makeBufferWithContents(new Uint32Array(indexData), GPUBufferUsage.INDEX);
} }

View File

@@ -6,8 +6,8 @@ and parameters as expect.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { kVertexFormatInfo } from '../../../../../capability_info.js'; import { kVertexFormatInfo } from '../../../../../capability_info.js';
import { GPUTest } from '../../../../../gpu_test.js'; import { GPUTest, AllFeaturesMaxLimitsGPUTest } from '../../../../../gpu_test.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; import * as vtu from '../../../validation_test_utils.js';
type VertexAttrib<A> = A & { shaderLocation: number }; type VertexAttrib<A> = A & { shaderLocation: number };
type VertexBuffer<V, A> = V & { type VertexBuffer<V, A> = V & {
@@ -98,7 +98,7 @@ function callDraw(
} }
function makeTestPipeline( function makeTestPipeline(
test: AllFeaturesMaxLimitsValidationTest, test: AllFeaturesMaxLimitsGPUTest,
buffers: VertexState< buffers: VertexState<
{ stepMode: GPUVertexStepMode; arrayStride: number }, { stepMode: GPUVertexStepMode; arrayStride: number },
{ {
@@ -116,14 +116,14 @@ function makeTestPipeline(
layout: 'auto', layout: 'auto',
vertex: { vertex: {
module: test.device.createShaderModule({ module: test.device.createShaderModule({
code: test.getNoOpShaderCode('VERTEX'), code: vtu.getNoOpShaderCode('VERTEX'),
}), }),
entryPoint: 'main', entryPoint: 'main',
buffers: bufferLayouts, buffers: bufferLayouts,
}, },
fragment: { fragment: {
module: test.device.createShaderModule({ module: test.device.createShaderModule({
code: test.getNoOpShaderCode('FRAGMENT'), code: vtu.getNoOpShaderCode('FRAGMENT'),
}), }),
entryPoint: 'main', entryPoint: 'main',
targets: [{ format: 'rgba8unorm', writeMask: 0 }], targets: [{ format: 'rgba8unorm', writeMask: 0 }],
@@ -133,7 +133,7 @@ function makeTestPipeline(
} }
function makeTestPipelineWithVertexAndInstanceBuffer( function makeTestPipelineWithVertexAndInstanceBuffer(
test: AllFeaturesMaxLimitsValidationTest, test: AllFeaturesMaxLimitsGPUTest,
arrayStride: number, arrayStride: number,
attributeFormat: GPUVertexFormat, attributeFormat: GPUVertexFormat,
attributeOffset: number = 0 attributeOffset: number = 0
@@ -190,7 +190,7 @@ const kDefaultParameterForIndexedDraw = {
indexBufferSize: 2 * 200, // exact required bound size for index buffer indexBufferSize: 2 * 200, // exact required bound size for index buffer
}; };
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test(`unused_buffer_bound`) g.test(`unused_buffer_bound`)
.desc( .desc(
@@ -226,16 +226,16 @@ In this test we test that a small buffer bound to unused buffer slot won't cause
bufferOffset, bufferOffset,
boundSize, boundSize,
} = t.params; } = t.params;
const renderPipeline = t.createNoOpRenderPipeline(); const renderPipeline = vtu.createNoOpRenderPipeline(t);
const bufferSize = bufferOffset + boundSize; const bufferSize = bufferOffset + boundSize;
const smallBuffer = t.createBufferWithState('valid', { const smallBuffer = vtu.createBufferWithState(t, 'valid', {
size: bufferSize, size: bufferSize,
usage: GPUBufferUsage.INDEX | GPUBufferUsage.VERTEX, usage: GPUBufferUsage.INDEX | GPUBufferUsage.VERTEX,
}); });
// An index buffer of enough size, used if smallIndexBuffer === false // An index buffer of enough size, used if smallIndexBuffer === false
const { indexFormat, indexBufferSize } = kDefaultParameterForIndexedDraw; const { indexFormat, indexBufferSize } = kDefaultParameterForIndexedDraw;
const indexBuffer = t.createBufferWithState('valid', { const indexBuffer = vtu.createBufferWithState(t, 'valid', {
size: indexBufferSize, size: indexBufferSize,
usage: GPUBufferUsage.INDEX, usage: GPUBufferUsage.INDEX,
}); });
@@ -320,7 +320,7 @@ drawIndexedIndirect as it is GPU-validated.
size: bufferSize, size: bufferSize,
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST, usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
}; };
const indexBuffer = t.createBufferWithState('valid', desc); const indexBuffer = vtu.createBufferWithState(t, 'valid', desc);
const drawCallParam: DrawIndexedParameter = { const drawCallParam: DrawIndexedParameter = {
indexCount: drawIndexCount, indexCount: drawIndexCount,
@@ -331,7 +331,7 @@ drawIndexedIndirect as it is GPU-validated.
const isFinishSuccess = const isFinishSuccess =
drawIndexCount <= bindingSizeInElements || drawType === 'drawIndexedIndirect'; drawIndexCount <= bindingSizeInElements || drawType === 'drawIndexedIndirect';
const renderPipeline = t.createNoOpRenderPipeline(); const renderPipeline = vtu.createNoOpRenderPipeline(t);
for (const encoderType of ['render bundle', 'render pass'] as const) { for (const encoderType of ['render bundle', 'render pass'] as const) {
for (const setPipelineBeforeBuffer of [false, true]) { for (const setPipelineBeforeBuffer of [false, true]) {
@@ -514,11 +514,11 @@ success/error as expected. Such set of buffer parameters should include cases li
); );
const instanceBufferSize = setBufferOffset + setInstanceBufferSize; const instanceBufferSize = setBufferOffset + setInstanceBufferSize;
const vertexBuffer = t.createBufferWithState('valid', { const vertexBuffer = vtu.createBufferWithState(t, 'valid', {
size: vertexBufferSize, size: vertexBufferSize,
usage: GPUBufferUsage.VERTEX, usage: GPUBufferUsage.VERTEX,
}); });
const instanceBuffer = t.createBufferWithState('valid', { const instanceBuffer = vtu.createBufferWithState(t, 'valid', {
size: instanceBufferSize, size: instanceBufferSize,
usage: GPUBufferUsage.VERTEX, usage: GPUBufferUsage.VERTEX,
}); });
@@ -561,7 +561,7 @@ success/error as expected. Such set of buffer parameters should include cases li
size: indexBufferSize, size: indexBufferSize,
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST, usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
}; };
const indexBuffer = t.createBufferWithState('valid', desc); const indexBuffer = vtu.createBufferWithState(t, 'valid', desc);
const drawParam: DrawIndexedParameter = { const drawParam: DrawIndexedParameter = {
indexCount, indexCount,
@@ -679,7 +679,7 @@ buffer slot and index buffer will cause no validation error, with completely/par
requiredBufferSize = Math.max(requiredBufferSize, setIndexBufferOffset + setIndexBufferSize); requiredBufferSize = Math.max(requiredBufferSize, setIndexBufferOffset + setIndexBufferSize);
// Create the shared GPU buffer with both vertetx and index usage // Create the shared GPU buffer with both vertetx and index usage
const sharedBuffer = t.createBufferWithState('valid', { const sharedBuffer = vtu.createBufferWithState(t, 'valid', {
size: requiredBufferSize, size: requiredBufferSize,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.INDEX, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.INDEX,
}); });

View File

@@ -23,8 +23,8 @@ TODO: ensure existing tests cover these notes. Note many of these may be operati
`; `;
import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsGPUTest } from '../../../../../gpu_test.js';
import { nextAfterF32 } from '../../../../../util/math.js'; import { nextAfterF32 } from '../../../../../util/math.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js';
interface ViewportCall { interface ViewportCall {
x: number; x: number;
@@ -42,7 +42,7 @@ interface ScissorCall {
h: number; h: number;
} }
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
testViewportCall( testViewportCall(
success: boolean, success: boolean,
v: ViewportCall, v: ViewportCall,

View File

@@ -4,14 +4,14 @@ Validation tests for drawIndirect/drawIndexedIndirect on render pass and render
import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUConst } from '../../../../../constants.js'; import { GPUConst } from '../../../../../constants.js';
import { kResourceStates } from '../../../../../gpu_test.js'; import { kResourceStates, AllFeaturesMaxLimitsGPUTest } from '../../../../../gpu_test.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; import * as vtu from '../../../validation_test_utils.js';
import { kRenderEncodeTypeParams } from './render.js'; import { kRenderEncodeTypeParams } from './render.js';
const kIndirectDrawTestParams = kRenderEncodeTypeParams.combine('indexed', [true, false] as const); const kIndirectDrawTestParams = kRenderEncodeTypeParams.combine('indexed', [true, false] as const);
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
makeIndexBuffer(): GPUBuffer { makeIndexBuffer(): GPUBuffer {
return this.createBufferTracked({ return this.createBufferTracked({
size: 16, size: 16,
@@ -31,8 +31,8 @@ Tests indirect buffer must be valid.
.paramsSubcasesOnly(kIndirectDrawTestParams.combine('state', kResourceStates)) .paramsSubcasesOnly(kIndirectDrawTestParams.combine('state', kResourceStates))
.fn(t => { .fn(t => {
const { encoderType, indexed, state } = t.params; const { encoderType, indexed, state } = t.params;
const pipeline = t.createNoOpRenderPipeline(); const pipeline = vtu.createNoOpRenderPipeline(t);
const indirectBuffer = t.createBufferWithState(state, { const indirectBuffer = vtu.createBufferWithState(t, state, {
size: 256, size: 256,
usage: GPUBufferUsage.INDIRECT, usage: GPUBufferUsage.INDIRECT,
}); });
@@ -69,7 +69,7 @@ g.test('indirect_buffer,device_mismatch')
); );
const { encoder, validateFinish } = t.createEncoder(encoderType); const { encoder, validateFinish } = t.createEncoder(encoderType);
encoder.setPipeline(t.createNoOpRenderPipeline()); encoder.setPipeline(vtu.createNoOpRenderPipeline(t));
if (indexed) { if (indexed) {
encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32'); encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32');
@@ -101,7 +101,7 @@ Tests indirect buffer must have 'Indirect' usage.
}); });
const { encoder, validateFinish } = t.createEncoder(encoderType); const { encoder, validateFinish } = t.createEncoder(encoderType);
encoder.setPipeline(t.createNoOpRenderPipeline()); encoder.setPipeline(vtu.createNoOpRenderPipeline(t));
if (indexed) { if (indexed) {
const indexBuffer = t.makeIndexBuffer(); const indexBuffer = t.makeIndexBuffer();
encoder.setIndexBuffer(indexBuffer, 'uint32'); encoder.setIndexBuffer(indexBuffer, 'uint32');
@@ -121,7 +121,7 @@ Tests indirect offset must be a multiple of 4.
.paramsSubcasesOnly(kIndirectDrawTestParams.combine('indirectOffset', [0, 2, 4] as const)) .paramsSubcasesOnly(kIndirectDrawTestParams.combine('indirectOffset', [0, 2, 4] as const))
.fn(t => { .fn(t => {
const { encoderType, indexed, indirectOffset } = t.params; const { encoderType, indexed, indirectOffset } = t.params;
const pipeline = t.createNoOpRenderPipeline(); const pipeline = vtu.createNoOpRenderPipeline(t);
const indirectBuffer = t.createBufferTracked({ const indirectBuffer = t.createBufferTracked({
size: 256, size: 256,
usage: GPUBufferUsage.INDIRECT, usage: GPUBufferUsage.INDIRECT,
@@ -181,7 +181,7 @@ Tests indirect draw calls with various indirect offsets and buffer sizes.
) )
.fn(t => { .fn(t => {
const { encoderType, indexed, indirectOffset, bufferSize, _valid } = t.params; const { encoderType, indexed, indirectOffset, bufferSize, _valid } = t.params;
const pipeline = t.createNoOpRenderPipeline(); const pipeline = vtu.createNoOpRenderPipeline(t);
const indirectBuffer = t.createBufferTracked({ const indirectBuffer = t.createBufferTracked({
size: bufferSize, size: bufferSize,
usage: GPUBufferUsage.INDIRECT, usage: GPUBufferUsage.INDIRECT,

View File

@@ -9,14 +9,14 @@ import {
kMaxUnsignedLongValue, kMaxUnsignedLongValue,
kMaxUnsignedLongLongValue, kMaxUnsignedLongLongValue,
} from '../../../../../constants.js'; } from '../../../../../constants.js';
import { kResourceStates } from '../../../../../gpu_test.js'; import { kResourceStates, AllFeaturesMaxLimitsGPUTest } from '../../../../../gpu_test.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; import * as vtu from '../../../validation_test_utils.js';
const kIndirectMultiDrawTestParams = kUnitCaseParamsBuilder const kIndirectMultiDrawTestParams = kUnitCaseParamsBuilder
.combine('indexed', [true, false] as const) .combine('indexed', [true, false] as const)
.combine('useDrawCountBuffer', [true, false] as const); .combine('useDrawCountBuffer', [true, false] as const);
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
makeIndexBuffer(): GPUBuffer { makeIndexBuffer(): GPUBuffer {
return this.createBufferTracked({ return this.createBufferTracked({
size: 16, size: 16,
@@ -50,19 +50,19 @@ Tests indirect and draw count buffers must be valid.
.fn(t => { .fn(t => {
t.skipIfDeviceDoesNotHaveFeature('chromium-experimental-multi-draw-indirect' as GPUFeatureName); t.skipIfDeviceDoesNotHaveFeature('chromium-experimental-multi-draw-indirect' as GPUFeatureName);
const { indexed, indirectState, useDrawCountBuffer, drawCountState } = t.params; const { indexed, indirectState, useDrawCountBuffer, drawCountState } = t.params;
const indirectBuffer = t.createBufferWithState(indirectState, { const indirectBuffer = vtu.createBufferWithState(t, indirectState, {
size: 256, size: 256,
usage: GPUBufferUsage.INDIRECT, usage: GPUBufferUsage.INDIRECT,
}); });
const drawCountBuffer = useDrawCountBuffer const drawCountBuffer = useDrawCountBuffer
? t.createBufferWithState(drawCountState, { ? vtu.createBufferWithState(t, drawCountState, {
size: 256, size: 256,
usage: GPUBufferUsage.INDIRECT, usage: GPUBufferUsage.INDIRECT,
}) })
: undefined; : undefined;
const { encoder, validateFinishAndSubmit } = t.createEncoder('render pass'); const { encoder, validateFinishAndSubmit } = t.createEncoder('render pass');
encoder.setPipeline(t.createNoOpRenderPipeline()); encoder.setPipeline(vtu.createNoOpRenderPipeline(t));
if (indexed) { if (indexed) {
encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32'); encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32');
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -117,7 +117,7 @@ g.test('buffers,device_mismatch')
: undefined; : undefined;
const { encoder, validateFinish } = t.createEncoder('render pass'); const { encoder, validateFinish } = t.createEncoder('render pass');
encoder.setPipeline(t.createNoOpRenderPipeline()); encoder.setPipeline(vtu.createNoOpRenderPipeline(t));
if (indexed) { if (indexed) {
encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32'); encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32');
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -164,7 +164,7 @@ Tests indirect and draw count buffers must have 'Indirect' usage.
: undefined; : undefined;
const { encoder, validateFinish } = t.createEncoder('render pass'); const { encoder, validateFinish } = t.createEncoder('render pass');
encoder.setPipeline(t.createNoOpRenderPipeline()); encoder.setPipeline(vtu.createNoOpRenderPipeline(t));
if (indexed) { if (indexed) {
encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32'); encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32');
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -214,7 +214,7 @@ Tests indirect and draw count offsets must be a multiple of 4.
: undefined; : undefined;
const { encoder, validateFinish } = t.createEncoder('render pass'); const { encoder, validateFinish } = t.createEncoder('render pass');
encoder.setPipeline(t.createNoOpRenderPipeline()); encoder.setPipeline(vtu.createNoOpRenderPipeline(t));
if (indexed) { if (indexed) {
encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32'); encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32');
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -288,7 +288,7 @@ Tests multi indirect draw calls with various indirect offsets and buffer sizes w
}); });
const { encoder, validateFinish } = t.createEncoder('render pass'); const { encoder, validateFinish } = t.createEncoder('render pass');
encoder.setPipeline(t.createNoOpRenderPipeline()); encoder.setPipeline(vtu.createNoOpRenderPipeline(t));
if (indexed) { if (indexed) {
encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32'); encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32');
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -339,7 +339,7 @@ Tests multi indirect draw calls with various draw count offsets, and draw count
}); });
const { encoder, validateFinish } = t.createEncoder('render pass'); const { encoder, validateFinish } = t.createEncoder('render pass');
encoder.setPipeline(t.createNoOpRenderPipeline()); encoder.setPipeline(vtu.createNoOpRenderPipeline(t));
if (indexed) { if (indexed) {
encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32'); encoder.setIndexBuffer(t.makeIndexBuffer(), 'uint32');
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any

View File

@@ -4,12 +4,12 @@ Validation tests for setIndexBuffer on render pass and render bundle.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUConst } from '../../../../../constants.js'; import { GPUConst } from '../../../../../constants.js';
import { kResourceStates } from '../../../../../gpu_test.js'; import { kResourceStates, AllFeaturesMaxLimitsGPUTest } from '../../../../../gpu_test.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; import * as vtu from '../../../validation_test_utils.js';
import { kRenderEncodeTypeParams, buildBufferOffsetAndSizeOOBTestParams } from './render.js'; import { kRenderEncodeTypeParams, buildBufferOffsetAndSizeOOBTestParams } from './render.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('index_buffer_state') g.test('index_buffer_state')
.desc( .desc(
@@ -20,7 +20,7 @@ Tests index buffer must be valid.
.paramsSubcasesOnly(kRenderEncodeTypeParams.combine('state', kResourceStates)) .paramsSubcasesOnly(kRenderEncodeTypeParams.combine('state', kResourceStates))
.fn(t => { .fn(t => {
const { encoderType, state } = t.params; const { encoderType, state } = t.params;
const indexBuffer = t.createBufferWithState(state, { const indexBuffer = vtu.createBufferWithState(t, state, {
size: 16, size: 16,
usage: GPUBufferUsage.INDEX, usage: GPUBufferUsage.INDEX,
}); });

View File

@@ -3,12 +3,13 @@ Validation tests for setPipeline on render pass and render bundle.
`; `;
import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsGPUTest } from '../../../../../gpu_test.js';
import { kRenderEncodeTypes } from '../../../../../util/command_buffer_maker.js'; import { kRenderEncodeTypes } from '../../../../../util/command_buffer_maker.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; import * as vtu from '../../../validation_test_utils.js';
import { kRenderEncodeTypeParams } from './render.js'; import { kRenderEncodeTypeParams } from './render.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('invalid_pipeline') g.test('invalid_pipeline')
.desc( .desc(
@@ -21,7 +22,7 @@ Tests setPipeline should generate an error iff using an 'invalid' pipeline.
) )
.fn(t => { .fn(t => {
const { encoderType, state } = t.params; const { encoderType, state } = t.params;
const pipeline = t.createRenderPipelineWithState(state); const pipeline = vtu.createRenderPipelineWithState(t, state);
const { encoder, validateFinish } = t.createEncoder(encoderType); const { encoder, validateFinish } = t.createEncoder(encoderType);
encoder.setPipeline(pipeline); encoder.setPipeline(pipeline);

View File

@@ -5,12 +5,12 @@ Validation tests for setVertexBuffer on render pass and render bundle.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { makeValueTestVariant } from '../../../../../../common/util/util.js'; import { makeValueTestVariant } from '../../../../../../common/util/util.js';
import { GPUConst } from '../../../../../constants.js'; import { GPUConst } from '../../../../../constants.js';
import { kResourceStates } from '../../../../../gpu_test.js'; import { kResourceStates, AllFeaturesMaxLimitsGPUTest } from '../../../../../gpu_test.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; import * as vtu from '../../../validation_test_utils.js';
import { kRenderEncodeTypeParams, buildBufferOffsetAndSizeOOBTestParams } from './render.js'; import { kRenderEncodeTypeParams, buildBufferOffsetAndSizeOOBTestParams } from './render.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('slot') g.test('slot')
.desc( .desc(
@@ -30,7 +30,7 @@ Tests slot must be less than the maxVertexBuffers in device limits.
const maxVertexBuffers = t.device.limits.maxVertexBuffers; const maxVertexBuffers = t.device.limits.maxVertexBuffers;
const slot = makeValueTestVariant(maxVertexBuffers, slotVariant); const slot = makeValueTestVariant(maxVertexBuffers, slotVariant);
const vertexBuffer = t.createBufferWithState('valid', { const vertexBuffer = vtu.createBufferWithState(t, 'valid', {
size: 16, size: 16,
usage: GPUBufferUsage.VERTEX, usage: GPUBufferUsage.VERTEX,
}); });
@@ -49,7 +49,7 @@ Tests vertex buffer must be valid.
.paramsSubcasesOnly(kRenderEncodeTypeParams.combine('state', kResourceStates)) .paramsSubcasesOnly(kRenderEncodeTypeParams.combine('state', kResourceStates))
.fn(t => { .fn(t => {
const { encoderType, state } = t.params; const { encoderType, state } = t.params;
const vertexBuffer = t.createBufferWithState(state, { const vertexBuffer = vtu.createBufferWithState(t, state, {
size: 16, size: 16,
usage: GPUBufferUsage.VERTEX, usage: GPUBufferUsage.VERTEX,
}); });

View File

@@ -4,9 +4,9 @@ Validation tests for setVertexBuffer/setIndexBuffer state (not validation). See
import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { range } from '../../../../../../common/util/util.js'; import { range } from '../../../../../../common/util/util.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../../../gpu_test.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
getVertexBuffer(): GPUBuffer { getVertexBuffer(): GPUBuffer {
return this.createBufferTracked({ return this.createBufferTracked({
size: 256, size: 256,

View File

@@ -9,6 +9,6 @@ TODO:
`; `;
import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);

View File

@@ -17,14 +17,18 @@ import {
kMinDynamicBufferOffsetAlignment, kMinDynamicBufferOffsetAlignment,
} from '../../../../capability_info.js'; } from '../../../../capability_info.js';
import { GPUConst } from '../../../../constants.js'; import { GPUConst } from '../../../../constants.js';
import { kResourceStates, ResourceState } from '../../../../gpu_test.js'; import {
kResourceStates,
ResourceState,
AllFeaturesMaxLimitsGPUTest,
} from '../../../../gpu_test.js';
import { import {
kProgrammableEncoderTypes, kProgrammableEncoderTypes,
ProgrammableEncoderType, ProgrammableEncoderType,
} from '../../../../util/command_buffer_maker.js'; } from '../../../../util/command_buffer_maker.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; import * as vtu from '../../validation_test_utils.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
encoderTypeToStageFlag(encoderType: ProgrammableEncoderType): GPUShaderStageFlags { encoderTypeToStageFlag(encoderType: ProgrammableEncoderType): GPUShaderStageFlags {
switch (encoderType) { switch (encoderType) {
case 'compute pass': case 'compute pass':
@@ -43,7 +47,7 @@ class F extends AllFeaturesMaxLimitsValidationTest {
): GPUBindingResource { ): GPUBindingResource {
switch (resourceType) { switch (resourceType) {
case 'texture': { case 'texture': {
const texture = this.createTextureWithState('valid'); const texture = vtu.createTextureWithState(this, 'valid');
const view = texture.createView(); const view = texture.createView();
if (state === 'destroyed') { if (state === 'destroyed') {
texture.destroy(); texture.destroy();
@@ -52,7 +56,7 @@ class F extends AllFeaturesMaxLimitsValidationTest {
} }
case 'buffer': case 'buffer':
return { return {
buffer: this.createBufferWithState(state, { buffer: vtu.createBufferWithState(this, state, {
size: 4, size: 4,
usage: GPUBufferUsage.UNIFORM, usage: GPUBufferUsage.UNIFORM,
}), }),
@@ -358,7 +362,7 @@ g.test('u32array_start_and_length')
entries: range(dynamicOffsetsDataLength, i => ({ entries: range(dynamicOffsetsDataLength, i => ({
binding: i, binding: i,
resource: { resource: {
buffer: t.createBufferWithState('valid', { buffer: vtu.createBufferWithState(t, 'valid', {
size: kBindingSize, size: kBindingSize,
usage: GPUBufferUsage.UNIFORM, usage: GPUBufferUsage.UNIFORM,
}), }),

View File

@@ -16,13 +16,13 @@ import {
kDepthStencilFormats, kDepthStencilFormats,
kPossibleColorRenderableTextureFormats, kPossibleColorRenderableTextureFormats,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
// MAINTENANCE_TODO: This should be changed to kMaxColorAttachmentsToTest // MAINTENANCE_TODO: This should be changed to kMaxColorAttachmentsToTest
// when this is made a MaxLimitTest (see above). // when this is made a MaxLimitTest (see above).
const kMaxColorAttachments = getDefaultLimits('core').maxColorAttachments.default; const kMaxColorAttachments = getDefaultLimits('core').maxColorAttachments.default;
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('attachment_state,limits,maxColorAttachments') g.test('attachment_state,limits,maxColorAttachments')
.desc(`Tests that attachment state must have <= device.limits.maxColorAttachments.`) .desc(`Tests that attachment state must have <= device.limits.maxColorAttachments.`)

View File

@@ -6,11 +6,12 @@ GPURenderPassEncoder when the encoder is not finished.
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { keysOf } from '../../../../common/util/data_tables.js'; import { keysOf } from '../../../../common/util/data_tables.js';
import { unreachable } from '../../../../common/util/util.js'; import { unreachable } from '../../../../common/util/util.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import * as vtu from '../validation_test_utils.js';
import { beginRenderPassWithQuerySet } from './queries/common.js'; import { beginRenderPassWithQuerySet } from './queries/common.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
createRenderPipelineForTest(): GPURenderPipeline { createRenderPipelineForTest(): GPURenderPipeline {
return this.device.createRenderPipeline({ return this.device.createRenderPipeline({
layout: 'auto', layout: 'auto',
@@ -561,7 +562,7 @@ g.test('compute_pass_commands')
usage: GPUBufferUsage.INDIRECT, usage: GPUBufferUsage.INDIRECT,
}); });
const computePipeline = t.createNoOpComputePipeline(); const computePipeline = vtu.createNoOpComputePipeline(t);
const bindGroup = t.createBindGroupForTest(); const bindGroup = t.createBindGroupForTest();

View File

@@ -18,9 +18,9 @@ TODO:
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { objectEquals } from '../../../../common/util/util.js'; import { objectEquals } from '../../../../common/util/util.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
beginRenderPass(commandEncoder: GPUCommandEncoder, view: GPUTextureView): GPURenderPassEncoder { beginRenderPass(commandEncoder: GPUCommandEncoder, view: GPUTextureView): GPURenderPassEncoder {
return commandEncoder.beginRenderPass({ return commandEncoder.beginRenderPass({
colorAttachments: [ colorAttachments: [

View File

@@ -21,11 +21,12 @@ import {
ValidBindableResource, ValidBindableResource,
} from '../../../../capability_info.js'; } from '../../../../capability_info.js';
import { GPUConst } from '../../../../constants.js'; import { GPUConst } from '../../../../constants.js';
import { AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js';
import { import {
ProgrammableEncoderType, ProgrammableEncoderType,
kProgrammableEncoderTypes, kProgrammableEncoderTypes,
} from '../../../../util/command_buffer_maker.js'; } from '../../../../util/command_buffer_maker.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; import * as vtu from '../../validation_test_utils.js';
const kComputeCmds = ['dispatch', 'dispatchIndirect'] as const; const kComputeCmds = ['dispatch', 'dispatchIndirect'] as const;
type ComputeCmd = (typeof kComputeCmds)[number]; type ComputeCmd = (typeof kComputeCmds)[number];
@@ -71,7 +72,7 @@ const kCompatTestParams = kUnitCaseParamsBuilder
.expand('call', p => getTestCmds(p.encoderType)) .expand('call', p => getTestCmds(p.encoderType))
.combine('callWithZero', [true, false]); .combine('callWithZero', [true, false]);
class F extends AllFeaturesMaxLimitsValidationTest { class F extends AllFeaturesMaxLimitsGPUTest {
getIndexBuffer(): GPUBuffer { getIndexBuffer(): GPUBuffer {
return this.createBufferTracked({ return this.createBufferTracked({
size: 8 * Uint32Array.BYTES_PER_ELEMENT, size: 8 * Uint32Array.BYTES_PER_ELEMENT,
@@ -164,7 +165,7 @@ class F extends AllFeaturesMaxLimitsValidationTest {
createBindGroupWithLayout(bglEntries: Array<GPUBindGroupLayoutEntry>): GPUBindGroup { createBindGroupWithLayout(bglEntries: Array<GPUBindGroupLayoutEntry>): GPUBindGroup {
const bgEntries: Array<GPUBindGroupEntry> = []; const bgEntries: Array<GPUBindGroupEntry> = [];
for (const entry of bglEntries) { for (const entry of bglEntries) {
const resource = this.getBindingResource(this.getBindingResourceType(entry)); const resource = vtu.getBindingResource(this, this.getBindingResourceType(entry));
bgEntries.push({ bgEntries.push({
binding: entry.binding, binding: entry.binding,
resource, resource,
@@ -539,7 +540,7 @@ g.test('buffer_binding,render_pipeline')
); );
// Create fixed bindGroup // Create fixed bindGroup
const uniformBuffer = t.getUniformBuffer(); const uniformBuffer = vtu.getUniformBuffer(t);
const bindGroup = t.device.createBindGroup({ const bindGroup = t.device.createBindGroup({
entries: [ entries: [

View File

@@ -3,11 +3,11 @@ Validation for encoding begin/endable queries.
`; `;
import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js';
import { beginRenderPassWithQuerySet, createQuerySetWithType } from './common.js'; import { beginRenderPassWithQuerySet, createQuerySetWithType } from './common.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('occlusion_query,begin_end_balance') g.test('occlusion_query,begin_end_balance')
.desc( .desc(

View File

@@ -4,11 +4,12 @@ Validation for encoding queries.
import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { kQueryTypes } from '../../../../capability_info.js'; import { kQueryTypes } from '../../../../capability_info.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js';
import * as vtu from '../../validation_test_utils.js';
import { createQuerySetWithType } from './common.js'; import { createQuerySetWithType } from './common.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('occlusion_query,query_type') g.test('occlusion_query,query_type')
.desc( .desc(
@@ -40,7 +41,7 @@ Tests that begin occlusion query with a invalid query set that failed during cre
) )
.paramsSubcasesOnly(u => u.combine('querySetState', ['valid', 'invalid'] as const)) .paramsSubcasesOnly(u => u.combine('querySetState', ['valid', 'invalid'] as const))
.fn(t => { .fn(t => {
const occlusionQuerySet = t.createQuerySetWithState(t.params.querySetState); const occlusionQuerySet = vtu.createQuerySetWithState(t, t.params.querySetState);
const encoder = t.createEncoder('render pass', { occlusionQuerySet }); const encoder = t.createEncoder('render pass', { occlusionQuerySet });
encoder.encoder.beginOcclusionQuery(0); encoder.encoder.beginOcclusionQuery(0);
@@ -114,7 +115,7 @@ TODO: writeTimestamp is removed from the spec so it's skipped if it TypeErrors.
t.skipIfDeviceDoesNotSupportQueryType('timestamp'); t.skipIfDeviceDoesNotSupportQueryType('timestamp');
const { querySetState } = t.params; const { querySetState } = t.params;
const querySet = t.createQuerySetWithState(querySetState, { const querySet = vtu.createQuerySetWithState(t, querySetState, {
type: 'timestamp', type: 'timestamp',
count: 2, count: 2,
}); });

View File

@@ -3,10 +3,10 @@ Validation tests for resolveQuerySet.
`; `;
import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUConst } from '../../../../constants.js'; import { GPUConst } from '../../../../constants.js';
import { kResourceStates } from '../../../../gpu_test.js'; import { kResourceStates, AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js';
import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; import * as vtu from '../../validation_test_utils.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
export const kQueryCount = 2; export const kQueryCount = 2;
@@ -29,9 +29,9 @@ Tests that resolve query set must be with valid query set and destination buffer
const shouldBeValid = querySetState !== 'invalid' && destinationState !== 'invalid'; const shouldBeValid = querySetState !== 'invalid' && destinationState !== 'invalid';
const shouldSubmitSuccess = querySetState === 'valid' && destinationState === 'valid'; const shouldSubmitSuccess = querySetState === 'valid' && destinationState === 'valid';
const querySet = t.createQuerySetWithState(querySetState); const querySet = vtu.createQuerySetWithState(t, querySetState);
const destination = t.createBufferWithState(destinationState, { const destination = vtu.createBufferWithState(t, destinationState, {
size: kQueryCount * 8, size: kQueryCount * 8,
usage: GPUBufferUsage.QUERY_RESOLVE, usage: GPUBufferUsage.QUERY_RESOLVE,
}); });

View File

@@ -4,9 +4,9 @@ Tests execution of render bundles.
import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { kDepthStencilFormats } from '../../../format_info.js'; import { kDepthStencilFormats } from '../../../format_info.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('empty_bundle_list') g.test('empty_bundle_list')
.desc( .desc(

View File

@@ -2,12 +2,11 @@ export const description = `
getBindGroupLayout validation tests. getBindGroupLayout validation tests.
`; `;
import { AllFeaturesMaxLimitsGPUTest } from '../.././gpu_test.js';
import { makeTestGroup } from '../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../common/framework/test_group.js';
import { assert } from '../../../common/util/util.js'; import { assert } from '../../../common/util/util.js';
import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js'; export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest);
g.test('index_range,explicit_layout') g.test('index_range,explicit_layout')
.desc( .desc(

View File

@@ -2,6 +2,7 @@ export const description = `
GPUExternalTexture expiration mechanism validation tests. GPUExternalTexture expiration mechanism validation tests.
`; `;
import { AllFeaturesMaxLimitsGPUTest } from '../.././gpu_test.js';
import { makeTestGroup } from '../../../common/framework/test_group.js'; import { makeTestGroup } from '../../../common/framework/test_group.js';
import { assert } from '../../../common/util/util.js'; import { assert } from '../../../common/util/util.js';
import { import {
@@ -12,9 +13,7 @@ import {
waitForNextTask, waitForNextTask,
} from '../../web_platform/util.js'; } from '../../web_platform/util.js';
import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js'; class GPUExternalTextureExpireTest extends AllFeaturesMaxLimitsGPUTest {
class GPUExternalTextureExpireTest extends AllFeaturesMaxLimitsValidationTest {
submitCommandBuffer(bindGroup: GPUBindGroup, success: boolean): void { submitCommandBuffer(bindGroup: GPUBindGroup, success: boolean): void {
const kHeight = 16; const kHeight = 16;
const kWidth = 16; const kWidth = 16;

View File

@@ -11,6 +11,7 @@ import {
} from '../../../format_info.js'; } from '../../../format_info.js';
import { kResourceStates } from '../../../gpu_test.js'; import { kResourceStates } from '../../../gpu_test.js';
import { kImageCopyTypes } from '../../../util/texture/layout.js'; import { kImageCopyTypes } from '../../../util/texture/layout.js';
import * as vtu from '../validation_test_utils.js';
import { ImageCopyTest, formatCopyableWithMethod } from './image_copy.js'; import { ImageCopyTest, formatCopyableWithMethod } from './image_copy.js';
@@ -34,7 +35,7 @@ Test that the buffer must be valid and not destroyed.
const { method, state } = t.params; const { method, state } = t.params;
// A valid buffer. // A valid buffer.
const buffer = t.createBufferWithState(state, { const buffer = vtu.createBufferWithState(t, state, {
size: 16, size: 16,
usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
}); });

View File

@@ -12,11 +12,11 @@ import {
depthStencilBufferTextureCopySupported, depthStencilBufferTextureCopySupported,
depthStencilFormatAspectSize, depthStencilFormatAspectSize,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import { align } from '../../../util/math.js'; import { align } from '../../../util/math.js';
import { kBufferCopyAlignment, kBytesPerRowAlignment } from '../../../util/texture/layout.js'; import { kBufferCopyAlignment, kBytesPerRowAlignment } from '../../../util/texture/layout.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js';
class ImageCopyTest extends AllFeaturesMaxLimitsValidationTest { class ImageCopyTest extends AllFeaturesMaxLimitsGPUTest {
testCopyBufferToTexture( testCopyBufferToTexture(
source: GPUTexelCopyBufferInfo, source: GPUTexelCopyBufferInfo,
destination: GPUTexelCopyTextureInfo, destination: GPUTexelCopyTextureInfo,

View File

@@ -8,11 +8,11 @@ import {
canCopyFromAllAspectsOfTextureFormat, canCopyFromAllAspectsOfTextureFormat,
canCopyToAllAspectsOfTextureFormat, canCopyToAllAspectsOfTextureFormat,
} from '../../../format_info.js'; } from '../../../format_info.js';
import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
import { align } from '../../../util/math.js'; import { align } from '../../../util/math.js';
import { ImageCopyType } from '../../../util/texture/layout.js'; import { ImageCopyType } from '../../../util/texture/layout.js';
import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js';
export class ImageCopyTest extends AllFeaturesMaxLimitsValidationTest { export class ImageCopyTest extends AllFeaturesMaxLimitsGPUTest {
testRun( testRun(
textureCopyView: GPUTexelCopyTextureInfo, textureCopyView: GPUTexelCopyTextureInfo,
textureDataLayout: GPUTexelCopyBufferLayout, textureDataLayout: GPUTexelCopyBufferLayout,

View File

@@ -17,6 +17,7 @@ import { kResourceStates } from '../../../gpu_test.js';
import { align } from '../../../util/math.js'; import { align } from '../../../util/math.js';
import { virtualMipSize } from '../../../util/texture/base.js'; import { virtualMipSize } from '../../../util/texture/base.js';
import { kImageCopyTypes } from '../../../util/texture/layout.js'; import { kImageCopyTypes } from '../../../util/texture/layout.js';
import * as vtu from '../validation_test_utils.js';
import { import {
ImageCopyTest, ImageCopyTest,
@@ -50,7 +51,7 @@ Test that the texture must be valid and not destroyed.
.fn(t => { .fn(t => {
const { method, textureState, size, dimension } = t.params; const { method, textureState, size, dimension } = t.params;
const texture = t.createTextureWithState(textureState, { const texture = vtu.createTextureWithState(t, textureState, {
size, size,
dimension, dimension,
format: 'rgba8unorm', format: 'rgba8unorm',

Some files were not shown because too many files have changed in this diff Show More