From 44173ed8c7bee555c02dd1e21b7bca0d383fe687 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Thu, 22 Dec 2022 19:44:58 -0500 Subject: [PATCH] Test all stencil formats, and address some nits in depth_bias/stencil tests (#2096) * make depth_bias expectations params private * remove infinity cases, WebIDL throws an exception in these cases * spencil -> stencil * Parameterize stencil tests over all stencil formats * make stencil expectation params private --- .../operation/rendering/depth_bias.spec.ts | 57 +++--- .../api/operation/rendering/stencil.spec.ts | 175 ++++++++++-------- 2 files changed, 119 insertions(+), 113 deletions(-) diff --git a/src/webgpu/api/operation/rendering/depth_bias.spec.ts b/src/webgpu/api/operation/rendering/depth_bias.spec.ts index cf7eace6e7eb..01e2dc904d6f 100644 --- a/src/webgpu/api/operation/rendering/depth_bias.spec.ts +++ b/src/webgpu/api/operation/rendering/depth_bias.spec.ts @@ -1,5 +1,5 @@ export const description = ` -Tests render results with different depth bias values like 'positive', 'negative', 'infinity', +Tests render results with different depth bias values like 'positive', 'negative', 'slope', 'clamp', etc. `; @@ -11,7 +11,6 @@ import { kTextureFormatInfo, } from '../../../capability_info.js'; import { GPUTest } from '../../../gpu_test.js'; -import { kValue } from '../../../util/constants.js'; import { TexelView } from '../../../util/texture/texel_view.js'; import { textureContentIsOKByT2B } from '../../../util/texture/texture_ok.js'; @@ -155,13 +154,13 @@ class DepthBiasTest extends GPUTest { bias, biasSlopeScale, biasClamp, - expectedDepth, + _expectedDepth, }: { quadAngle: QuadAngle; bias: number; biasSlopeScale: number; biasClamp: number; - expectedDepth: number; + _expectedDepth: number; } ) { const { renderTarget, depthTexture } = this.runDepthBiasTestInternal(depthFormat, { @@ -172,7 +171,7 @@ class DepthBiasTest extends GPUTest { initialDepth: 0, }); - const expColor = { Depth: expectedDepth }; + const expColor = { Depth: _expectedDepth }; const expTexelView = TexelView.fromTexelsAsColors(depthFormat, coords => expColor); const result = textureContentIsOKByT2B( @@ -194,13 +193,13 @@ class DepthBiasTest extends GPUTest { bias, biasSlopeScale, biasClamp, - expectedColor, + _expectedColor, }: { quadAngle: QuadAngle; bias: number; biasSlopeScale: number; biasClamp: number; - expectedColor: Float32Array; + _expectedColor: Float32Array; } ) { const { renderTarget, depthTexture } = this.runDepthBiasTestInternal(depthFormat, { @@ -213,10 +212,10 @@ class DepthBiasTest extends GPUTest { const renderTargetFormat = 'rgba8unorm'; const expColor = { - R: expectedColor[0], - G: expectedColor[1], - B: expectedColor[2], - A: expectedColor[3], + R: _expectedColor[0], + G: _expectedColor[1], + B: _expectedColor[2], + A: _expectedColor[3], }; const expTexelView = TexelView.fromTexelsAsColors(renderTargetFormat, coords => expColor); @@ -264,7 +263,7 @@ export const g = makeTestGroup(DepthBiasTest); g.test('depth_bias') .desc( ` - Tests that a square with different depth bias values like 'positive', 'negative', 'infinity', + Tests that a square with different depth bias values like 'positive', 'negative', 'slope', 'clamp', etc. is drawn as expected. ` ) @@ -276,63 +275,49 @@ g.test('depth_bias') bias: kPointTwoFiveBiasForPointTwoFiveZOnFloat, biasSlopeScale: 0, biasClamp: 0, - expectedDepth: 0.5, + _expectedDepth: 0.5, }, { quadAngle: QuadAngle.Flat, bias: kPointTwoFiveBiasForPointTwoFiveZOnFloat, biasSlopeScale: 0, biasClamp: 0.125, - expectedDepth: 0.375, + _expectedDepth: 0.375, }, { quadAngle: QuadAngle.Flat, bias: -kPointTwoFiveBiasForPointTwoFiveZOnFloat, biasSlopeScale: 0, biasClamp: 0.125, - expectedDepth: 0, + _expectedDepth: 0, }, { quadAngle: QuadAngle.Flat, bias: -kPointTwoFiveBiasForPointTwoFiveZOnFloat, biasSlopeScale: 0, biasClamp: -0.125, - expectedDepth: 0.125, + _expectedDepth: 0.125, }, { quadAngle: QuadAngle.TiltedX, bias: 0, biasSlopeScale: 0, biasClamp: 0, - expectedDepth: 0.25, + _expectedDepth: 0.25, }, { quadAngle: QuadAngle.TiltedX, bias: 0, biasSlopeScale: 1, biasClamp: 0, - expectedDepth: 0.75, + _expectedDepth: 0.75, }, { quadAngle: QuadAngle.TiltedX, bias: 0, biasSlopeScale: -0.5, biasClamp: 0, - expectedDepth: 0, - }, - { - quadAngle: QuadAngle.TiltedX, - bias: 0, - biasSlopeScale: kValue.f32.infinity.positive, - biasClamp: 0, - expectedDepth: 1, - }, - { - quadAngle: QuadAngle.TiltedX, - bias: 0, - biasSlopeScale: kValue.f32.infinity.negative, - biasClamp: 0, - expectedDepth: 0, + _expectedDepth: 0, }, ] as const) ) @@ -360,21 +345,21 @@ g.test('depth_bias_24bit_format') bias: 0.25 * (1 << 25), biasSlopeScale: 0, biasClamp: 0, - expectedColor: new Float32Array([1.0, 0.0, 0.0, 1.0]), + _expectedColor: new Float32Array([1.0, 0.0, 0.0, 1.0]), }, { quadAngle: QuadAngle.TiltedX, bias: 0.25 * (1 << 25), biasSlopeScale: 1, biasClamp: 0, - expectedColor: new Float32Array([1.0, 0.0, 0.0, 1.0]), + _expectedColor: new Float32Array([1.0, 0.0, 0.0, 1.0]), }, { quadAngle: QuadAngle.Flat, bias: 0.25 * (1 << 25), biasSlopeScale: 0, biasClamp: 0.1, - expectedColor: new Float32Array([0.0, 0.0, 0.0, 0.0]), + _expectedColor: new Float32Array([0.0, 0.0, 0.0, 0.0]), }, ] as const) ) diff --git a/src/webgpu/api/operation/rendering/stencil.spec.ts b/src/webgpu/api/operation/rendering/stencil.spec.ts index e6c3c0cd079a..5985616a54d6 100644 --- a/src/webgpu/api/operation/rendering/stencil.spec.ts +++ b/src/webgpu/api/operation/rendering/stencil.spec.ts @@ -4,11 +4,17 @@ Test related to stencil states, stencil op, compare func, etc. import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { TypedArrayBufferView } from '../../../../common/util/util.js'; -import { kDepthStencilFormats, kTextureFormatInfo } from '../../../capability_info.js'; +import { + DepthStencilFormat, + kDepthStencilFormats, + kTextureFormatInfo, +} from '../../../capability_info.js'; import { GPUTest } from '../../../gpu_test.js'; import { TexelView } from '../../../util/texture/texel_view.js'; import { textureContentIsOKByT2B } from '../../../util/texture/texture_ok.js'; +const kStencilFormats = kDepthStencilFormats.filter(format => kTextureFormatInfo[format].stencil); + const kBaseColor = new Float32Array([1.0, 1.0, 1.0, 1.0]); const kRedStencilColor = new Float32Array([1.0, 0.0, 0.0, 1.0]); const kGreenStencilColor = new Float32Array([0.0, 1.0, 0.0, 1.0]); @@ -21,13 +27,12 @@ type TestStates = { class StencilTest extends GPUTest { checkStencilOperation( + depthStencilFormat: DepthStencilFormat, testStencilState: GPUStencilFaceState, initialStencil: number, - expectedStencil: number, + _expectedStencil: number, depthCompare: GPUCompareFunction = 'always' ) { - const depthStencilFormat: GPUTextureFormat = 'depth24plus-stencil8'; - const kReferenceStencil = 3; const baseStencilState = { @@ -70,16 +75,16 @@ class StencilTest extends GPUTest { // Draw the base triangle with stencil reference 1. This clears the stencil buffer to 1. { state: baseState, color: kBaseColor, stencil: initialStencil }, { state: testState, color: kRedStencilColor, stencil: kReferenceStencil }, - { state: testState2, color: kGreenStencilColor, stencil: expectedStencil }, + { state: testState2, color: kGreenStencilColor, stencil: _expectedStencil }, ]; - this.runStencilStateTest(testStates, kGreenStencilColor); + this.runStencilStateTest(depthStencilFormat, testStates, kGreenStencilColor); } checkStencilCompareFunction( + depthStencilFormat: DepthStencilFormat, compareFunction: GPUCompareFunction, stencilRefValue: number, - expectedColor: Float32Array, - depthStencilFormat: GPUTextureFormat = 'depth24plus-stencil8' + expectedColor: Float32Array ) { const baseStencilState = { compare: 'always', @@ -114,14 +119,14 @@ class StencilTest extends GPUTest { { state: baseState, color: kBaseColor, stencil: 1 }, { state: testState, color: kGreenStencilColor, stencil: stencilRefValue }, ]; - this.runStencilStateTest(testStates, expectedColor, false, depthStencilFormat); + this.runStencilStateTest(depthStencilFormat, testStates, expectedColor); } runStencilStateTest( + depthStencilFormat: DepthStencilFormat, testStates: TestStates[], expectedColor: Float32Array, - isSingleEncoderMultiplePass: boolean = false, - depthStencilFormat: GPUTextureFormat = 'depth24plus-stencil8' + isSingleEncoderMultiplePass: boolean = false ) { const renderTargetFormat = 'rgba8unorm'; const renderTarget = this.device.createTexture({ @@ -276,10 +281,7 @@ g.test('stencil_compare_func') ) .params(u => u // - .combine( - 'depthStencilFormat', - kDepthStencilFormats.filter(format => kTextureFormatInfo[format].stencil) - ) + .combine('format', kStencilFormats) .combineWithParams([ { stencilCompare: 'always', stencilRefValue: 0, _expectedColor: kGreenStencilColor }, { stencilCompare: 'always', stencilRefValue: 1, _expectedColor: kGreenStencilColor }, @@ -308,17 +310,12 @@ g.test('stencil_compare_func') ] as const) ) .beforeAllSubcases(t => { - t.selectDeviceForTextureFormatOrSkipTestCase(t.params.depthStencilFormat); + t.selectDeviceForTextureFormatOrSkipTestCase(t.params.format); }) .fn(async t => { - const { depthStencilFormat, stencilCompare, stencilRefValue, _expectedColor } = t.params; + const { format, stencilCompare, stencilRefValue, _expectedColor } = t.params; - t.checkStencilCompareFunction( - stencilCompare, - stencilRefValue, - _expectedColor, - depthStencilFormat - ); + t.checkStencilCompareFunction(format, stencilCompare, stencilRefValue, _expectedColor); }); g.test('stencil_passOp_operation') @@ -334,23 +331,27 @@ g.test('stencil_passOp_operation') ) .params(u => u // + .combine('format', kStencilFormats) .combineWithParams([ - { passOp: 'keep', initialStencil: 1, expectedStencil: 1 }, - { passOp: 'zero', initialStencil: 1, expectedStencil: 0 }, - { passOp: 'replace', initialStencil: 1, expectedStencil: 3 }, - { passOp: 'invert', initialStencil: 0xf0, expectedStencil: 0x0f }, - { passOp: 'increment-clamp', initialStencil: 1, expectedStencil: 2 }, - { passOp: 'increment-clamp', initialStencil: 0xff, expectedStencil: 0xff }, - { passOp: 'increment-wrap', initialStencil: 1, expectedStencil: 2 }, - { passOp: 'increment-wrap', initialStencil: 0xff, expectedStencil: 0 }, - { passOp: 'decrement-clamp', initialStencil: 1, expectedStencil: 0 }, - { passOp: 'decrement-clamp', initialStencil: 0, expectedStencil: 0 }, - { passOp: 'decrement-wrap', initialStencil: 1, expectedStencil: 0 }, - { passOp: 'decrement-wrap', initialStencil: 0, expectedStencil: 0xff }, + { passOp: 'keep', initialStencil: 1, _expectedStencil: 1 }, + { passOp: 'zero', initialStencil: 1, _expectedStencil: 0 }, + { passOp: 'replace', initialStencil: 1, _expectedStencil: 3 }, + { passOp: 'invert', initialStencil: 0xf0, _expectedStencil: 0x0f }, + { passOp: 'increment-clamp', initialStencil: 1, _expectedStencil: 2 }, + { passOp: 'increment-clamp', initialStencil: 0xff, _expectedStencil: 0xff }, + { passOp: 'increment-wrap', initialStencil: 1, _expectedStencil: 2 }, + { passOp: 'increment-wrap', initialStencil: 0xff, _expectedStencil: 0 }, + { passOp: 'decrement-clamp', initialStencil: 1, _expectedStencil: 0 }, + { passOp: 'decrement-clamp', initialStencil: 0, _expectedStencil: 0 }, + { passOp: 'decrement-wrap', initialStencil: 1, _expectedStencil: 0 }, + { passOp: 'decrement-wrap', initialStencil: 0, _expectedStencil: 0xff }, ] as const) ) + .beforeAllSubcases(t => { + t.selectDeviceForTextureFormatOrSkipTestCase(t.params.format); + }) .fn(async t => { - const { passOp, initialStencil, expectedStencil } = t.params; + const { format, passOp, initialStencil, _expectedStencil } = t.params; const stencilState = { compare: 'always', @@ -358,7 +359,7 @@ g.test('stencil_passOp_operation') passOp, } as const; - t.checkStencilOperation(stencilState, initialStencil, expectedStencil); + t.checkStencilOperation(format, stencilState, initialStencil, _expectedStencil); }); g.test('stencil_failOp_operation') @@ -374,24 +375,28 @@ g.test('stencil_failOp_operation') ) .params(u => u // + .combine('format', kStencilFormats) .combineWithParams([ - { failOp: 'keep', initialStencil: 1, expectedStencil: 1 }, - { failOp: 'zero', initialStencil: 1, expectedStencil: 0 }, - { failOp: 'replace', initialStencil: 1, expectedStencil: 3 }, - { failOp: 'invert', initialStencil: 0xf0, expectedStencil: 0x0f }, - { failOp: 'increment-clamp', initialStencil: 1, expectedStencil: 2 }, - { failOp: 'increment-clamp', initialStencil: 0xff, expectedStencil: 0xff }, - { failOp: 'increment-wrap', initialStencil: 1, expectedStencil: 2 }, - { failOp: 'increment-wrap', initialStencil: 0xff, expectedStencil: 0 }, - { failOp: 'decrement-clamp', initialStencil: 1, expectedStencil: 0 }, - { failOp: 'decrement-clamp', initialStencil: 0, expectedStencil: 0 }, - { failOp: 'decrement-wrap', initialStencil: 2, expectedStencil: 1 }, - { failOp: 'decrement-wrap', initialStencil: 1, expectedStencil: 0 }, - { failOp: 'decrement-wrap', initialStencil: 0, expectedStencil: 0xff }, + { failOp: 'keep', initialStencil: 1, _expectedStencil: 1 }, + { failOp: 'zero', initialStencil: 1, _expectedStencil: 0 }, + { failOp: 'replace', initialStencil: 1, _expectedStencil: 3 }, + { failOp: 'invert', initialStencil: 0xf0, _expectedStencil: 0x0f }, + { failOp: 'increment-clamp', initialStencil: 1, _expectedStencil: 2 }, + { failOp: 'increment-clamp', initialStencil: 0xff, _expectedStencil: 0xff }, + { failOp: 'increment-wrap', initialStencil: 1, _expectedStencil: 2 }, + { failOp: 'increment-wrap', initialStencil: 0xff, _expectedStencil: 0 }, + { failOp: 'decrement-clamp', initialStencil: 1, _expectedStencil: 0 }, + { failOp: 'decrement-clamp', initialStencil: 0, _expectedStencil: 0 }, + { failOp: 'decrement-wrap', initialStencil: 2, _expectedStencil: 1 }, + { failOp: 'decrement-wrap', initialStencil: 1, _expectedStencil: 0 }, + { failOp: 'decrement-wrap', initialStencil: 0, _expectedStencil: 0xff }, ] as const) ) + .beforeAllSubcases(t => { + t.selectDeviceForTextureFormatOrSkipTestCase(t.params.format); + }) .fn(async t => { - const { failOp, initialStencil, expectedStencil } = t.params; + const { format, failOp, initialStencil, _expectedStencil } = t.params; const stencilState = { compare: 'never', @@ -402,7 +407,7 @@ g.test('stencil_failOp_operation') // Draw the base triangle with stencil reference 1. This clears the stencil buffer to 1. // Always fails because the comparison never passes. Therefore red is never drawn, and the // stencil contents may be updated according to `operation`. - t.checkStencilOperation(stencilState, initialStencil, expectedStencil); + t.checkStencilOperation(format, stencilState, initialStencil, _expectedStencil); }); g.test('stencil_depthFailOp_operation') @@ -418,24 +423,34 @@ g.test('stencil_depthFailOp_operation') ) .params(u => u // + .combine( + 'format', + kDepthStencilFormats.filter(format => { + const info = kTextureFormatInfo[format]; + return info.depth && info.stencil; + }) + ) .combineWithParams([ - { depthFailOp: 'keep', initialStencil: 1, expectedStencil: 1 }, - { depthFailOp: 'zero', initialStencil: 1, expectedStencil: 0 }, - { depthFailOp: 'replace', initialStencil: 1, expectedStencil: 3 }, - { depthFailOp: 'invert', initialStencil: 0xf0, expectedStencil: 0x0f }, - { depthFailOp: 'increment-clamp', initialStencil: 1, expectedStencil: 2 }, - { depthFailOp: 'increment-clamp', initialStencil: 0xff, expectedStencil: 0xff }, - { depthFailOp: 'increment-wrap', initialStencil: 1, expectedStencil: 2 }, - { depthFailOp: 'increment-wrap', initialStencil: 0xff, expectedStencil: 0 }, - { depthFailOp: 'decrement-clamp', initialStencil: 1, expectedStencil: 0 }, - { depthFailOp: 'decrement-clamp', initialStencil: 0, expectedStencil: 0 }, - { depthFailOp: 'decrement-wrap', initialStencil: 2, expectedStencil: 1 }, - { depthFailOp: 'decrement-wrap', initialStencil: 1, expectedStencil: 0 }, - { depthFailOp: 'decrement-wrap', initialStencil: 0, expectedStencil: 0xff }, + { depthFailOp: 'keep', initialStencil: 1, _expectedStencil: 1 }, + { depthFailOp: 'zero', initialStencil: 1, _expectedStencil: 0 }, + { depthFailOp: 'replace', initialStencil: 1, _expectedStencil: 3 }, + { depthFailOp: 'invert', initialStencil: 0xf0, _expectedStencil: 0x0f }, + { depthFailOp: 'increment-clamp', initialStencil: 1, _expectedStencil: 2 }, + { depthFailOp: 'increment-clamp', initialStencil: 0xff, _expectedStencil: 0xff }, + { depthFailOp: 'increment-wrap', initialStencil: 1, _expectedStencil: 2 }, + { depthFailOp: 'increment-wrap', initialStencil: 0xff, _expectedStencil: 0 }, + { depthFailOp: 'decrement-clamp', initialStencil: 1, _expectedStencil: 0 }, + { depthFailOp: 'decrement-clamp', initialStencil: 0, _expectedStencil: 0 }, + { depthFailOp: 'decrement-wrap', initialStencil: 2, _expectedStencil: 1 }, + { depthFailOp: 'decrement-wrap', initialStencil: 1, _expectedStencil: 0 }, + { depthFailOp: 'decrement-wrap', initialStencil: 0, _expectedStencil: 0xff }, ] as const) ) + .beforeAllSubcases(t => { + t.selectDeviceForTextureFormatOrSkipTestCase(t.params.format); + }) .fn(async t => { - const { depthFailOp, initialStencil, expectedStencil } = t.params; + const { format, depthFailOp, initialStencil, _expectedStencil } = t.params; const stencilState = { compare: 'always', @@ -446,7 +461,7 @@ g.test('stencil_depthFailOp_operation') // Call checkStencilOperation function with enabling the depthTest to test that the depthFailOp // stencil operation works as expected. - t.checkStencilOperation(stencilState, initialStencil, expectedStencil, 'never'); + t.checkStencilOperation(format, stencilState, initialStencil, _expectedStencil, 'never'); }); g.test('stencil_read_write_mask') @@ -469,6 +484,7 @@ g.test('stencil_read_write_mask') ) .params(u => u // + .combine('format', kStencilFormats) .combineWithParams([ { maskType: 'write', stencilRefValue: 1, _expectedColor: kRedStencilColor }, { maskType: 'write', stencilRefValue: 2, _expectedColor: kBaseColor }, @@ -476,10 +492,11 @@ g.test('stencil_read_write_mask') { maskType: 'read', stencilRefValue: 2, _expectedColor: kRedStencilColor }, ]) ) + .beforeAllSubcases(t => { + t.selectDeviceForTextureFormatOrSkipTestCase(t.params.format); + }) .fn(async t => { - const { maskType, stencilRefValue, _expectedColor } = t.params; - - const depthSpencilFormat: GPUTextureFormat = 'depth24plus-stencil8'; + const { format, maskType, stencilRefValue, _expectedColor } = t.params; const baseStencilState = { compare: 'always', @@ -494,7 +511,7 @@ g.test('stencil_read_write_mask') } as const; const baseState = { - format: depthSpencilFormat, + format, depthWriteEnabled: false, depthCompare: 'always', stencilFront: baseStencilState, @@ -504,7 +521,7 @@ g.test('stencil_read_write_mask') } as const; const testState = { - format: depthSpencilFormat, + format, depthWriteEnabled: false, depthCompare: 'always', stencilFront: stencilState, @@ -519,13 +536,17 @@ g.test('stencil_read_write_mask') { state: testState, color: kRedStencilColor, stencil: stencilRefValue }, ]; - t.runStencilStateTest(testStates, _expectedColor); + t.runStencilStateTest(format, testStates, _expectedColor); }); g.test('stencil_reference_initialized') .desc('Test that stencil reference is initialized as zero for new render pass.') + .params(u => u.combine('format', kStencilFormats)) + .beforeAllSubcases(t => { + t.selectDeviceForTextureFormatOrSkipTestCase(t.params.format); + }) .fn(async t => { - const depthSpencilFormat: GPUTextureFormat = 'depth24plus-stencil8'; + const { format } = t.params; const baseStencilState = { compare: 'always', @@ -538,13 +559,13 @@ g.test('stencil_reference_initialized') } as const; const baseState = { - format: depthSpencilFormat, + format, stencilFront: baseStencilState, stencilBack: baseStencilState, } as const; const testState = { - format: depthSpencilFormat, + format, stencilFront: testStencilState, stencilBack: testStencilState, } as const; @@ -558,5 +579,5 @@ g.test('stencil_reference_initialized') ]; // The third draw should pass the stencil test since the second pass set it to default zero. - t.runStencilStateTest(testStates, kGreenStencilColor, true); + t.runStencilStateTest(format, testStates, kGreenStencilColor, true); });