@@ -22,11 +22,13 @@ class StencilTest extends GPUTest {
2222 checkStencilOperation (
2323 testStencilState : GPUStencilFaceState ,
2424 initialStencil : number ,
25- referenceStencil : number ,
26- expectedStencil : number
25+ expectedStencil : number ,
26+ depthCompare : GPUCompareFunction = 'always'
2727 ) {
2828 const depthStencilFormat : GPUTextureFormat = 'depth24plus-stencil8' ;
2929
30+ const kReferenceStencil = 3 ;
31+
3032 const baseStencilState = {
3133 compare : 'always' ,
3234 failOp : 'keep' ,
@@ -50,7 +52,7 @@ class StencilTest extends GPUTest {
5052 const testState = {
5153 format : depthStencilFormat ,
5254 depthWriteEnabled : false ,
53- depthCompare : 'always' ,
55+ depthCompare,
5456 stencilFront : testStencilState ,
5557 stencilBack : testStencilState ,
5658 } as const ;
@@ -66,7 +68,7 @@ class StencilTest extends GPUTest {
6668 const testStates = [
6769 // Draw the base triangle with stencil reference 1. This clears the stencil buffer to 1.
6870 { state : baseState , color : kBaseColor , stencil : initialStencil } ,
69- { state : testState , color : kRedStencilColor , stencil : referenceStencil } ,
71+ { state : testState , color : kRedStencilColor , stencil : kReferenceStencil } ,
7072 { state : testState2 , color : kGreenStencilColor , stencil : expectedStencil } ,
7173 ] ;
7274 this . runStencilStateTest ( testStates , kGreenStencilColor ) ;
@@ -316,82 +318,35 @@ g.test('stencil_passOp_operation')
316318 - If the pass operation is 'keep', it keeps the initial stencil value.
317319 - If the pass operation is 'replace', it replaces the initial stencil value with the reference
318320 stencil value.
319-
320- TODO: Need to test depthFailOp as well.
321321 `
322322 )
323323 . params ( u =>
324324 u //
325325 . combineWithParams ( [
326- { passOp : 'keep' , initialStencil : 1 , referenceStencil : 3 , expectedStencil : 1 } ,
327- { passOp : 'zero' , initialStencil : 1 , referenceStencil : 3 , expectedStencil : 0 } ,
328- { passOp : 'replace' , initialStencil : 1 , referenceStencil : 3 , expectedStencil : 3 } ,
329- {
330- passOp : 'invert' ,
331- initialStencil : 0xf0 ,
332- referenceStencil : 3 ,
333- expectedStencil : 0x0f ,
334- } ,
335- {
336- passOp : 'increment-clamp' ,
337- initialStencil : 1 ,
338- referenceStencil : 3 ,
339- expectedStencil : 2 ,
340- } ,
341- {
342- passOp : 'increment-clamp' ,
343- initialStencil : 0xff ,
344- referenceStencil : 3 ,
345- expectedStencil : 0xff ,
346- } ,
347- {
348- passOp : 'increment-wrap' ,
349- initialStencil : 1 ,
350- referenceStencil : 3 ,
351- expectedStencil : 2 ,
352- } ,
353- {
354- passOp : 'increment-wrap' ,
355- initialStencil : 0xff ,
356- referenceStencil : 3 ,
357- expectedStencil : 0 ,
358- } ,
359- {
360- passOp : 'decrement-clamp' ,
361- initialStencil : 1 ,
362- referenceStencil : 3 ,
363- expectedStencil : 0 ,
364- } ,
365- {
366- passOp : 'decrement-clamp' ,
367- initialStencil : 0 ,
368- referenceStencil : 3 ,
369- expectedStencil : 0 ,
370- } ,
371- {
372- passOp : 'decrement-wrap' ,
373- initialStencil : 1 ,
374- referenceStencil : 3 ,
375- expectedStencil : 0 ,
376- } ,
377- {
378- passOp : 'decrement-wrap' ,
379- initialStencil : 0 ,
380- referenceStencil : 3 ,
381- expectedStencil : 0xff ,
382- } ,
326+ { passOp : 'keep' , initialStencil : 1 , expectedStencil : 1 } ,
327+ { passOp : 'zero' , initialStencil : 1 , expectedStencil : 0 } ,
328+ { passOp : 'replace' , initialStencil : 1 , expectedStencil : 3 } ,
329+ { passOp : 'invert' , initialStencil : 0xf0 , expectedStencil : 0x0f } ,
330+ { passOp : 'increment-clamp' , initialStencil : 1 , expectedStencil : 2 } ,
331+ { passOp : 'increment-clamp' , initialStencil : 0xff , expectedStencil : 0xff } ,
332+ { passOp : 'increment-wrap' , initialStencil : 1 , expectedStencil : 2 } ,
333+ { passOp : 'increment-wrap' , initialStencil : 0xff , expectedStencil : 0 } ,
334+ { passOp : 'decrement-clamp' , initialStencil : 1 , expectedStencil : 0 } ,
335+ { passOp : 'decrement-clamp' , initialStencil : 0 , expectedStencil : 0 } ,
336+ { passOp : 'decrement-wrap' , initialStencil : 1 , expectedStencil : 0 } ,
337+ { passOp : 'decrement-wrap' , initialStencil : 0 , expectedStencil : 0xff } ,
383338 ] as const )
384339 )
385340 . fn ( async t => {
386- const { passOp, initialStencil, referenceStencil , expectedStencil } = t . params ;
341+ const { passOp, initialStencil, expectedStencil } = t . params ;
387342
388343 const stencilState = {
389344 compare : 'always' ,
390345 failOp : 'keep' ,
391346 passOp,
392347 } as const ;
393348
394- t . checkStencilOperation ( stencilState , initialStencil , referenceStencil , expectedStencil ) ;
349+ t . checkStencilOperation ( stencilState , initialStencil , expectedStencil ) ;
395350 } ) ;
396351
397352g . test ( 'stencil_failOp_operation' )
@@ -426,8 +381,6 @@ g.test('stencil_failOp_operation')
426381 . fn ( async t => {
427382 const { failOp, initialStencil, expectedStencil } = t . params ;
428383
429- const kReferenceStencil = 3 ;
430-
431384 const stencilState = {
432385 compare : 'never' ,
433386 failOp,
@@ -437,7 +390,51 @@ g.test('stencil_failOp_operation')
437390 // Draw the base triangle with stencil reference 1. This clears the stencil buffer to 1.
438391 // Always fails because the comparison never passes. Therefore red is never drawn, and the
439392 // stencil contents may be updated according to `operation`.
440- t . checkStencilOperation ( stencilState , initialStencil , kReferenceStencil , expectedStencil ) ;
393+ t . checkStencilOperation ( stencilState , initialStencil , expectedStencil ) ;
394+ } ) ;
395+
396+ g . test ( 'stencil_depthFailOp_operation' )
397+ . desc (
398+ `
399+ Test that the stencil operation is executed on depthCompare fail. A triangle is drawn with the
400+ 'never' depthCompare, so it should fail the depth test. Then, test that each 'depthFailOp' stencil operation
401+ works with the given stencil values correctly as expected. For example,
402+ - If the depthFailOp operation is 'keep', it keeps the initial stencil value.
403+ - If the depthFailOp operation is 'replace', it replaces the initial stencil value with the
404+ reference stencil value.
405+ `
406+ )
407+ . params ( u =>
408+ u //
409+ . combineWithParams ( [
410+ { depthFailOp : 'keep' , initialStencil : 1 , expectedStencil : 1 } ,
411+ { depthFailOp : 'zero' , initialStencil : 1 , expectedStencil : 0 } ,
412+ { depthFailOp : 'replace' , initialStencil : 1 , expectedStencil : 3 } ,
413+ { depthFailOp : 'invert' , initialStencil : 0xf0 , expectedStencil : 0x0f } ,
414+ { depthFailOp : 'increment-clamp' , initialStencil : 1 , expectedStencil : 2 } ,
415+ { depthFailOp : 'increment-clamp' , initialStencil : 0xff , expectedStencil : 0xff } ,
416+ { depthFailOp : 'increment-wrap' , initialStencil : 1 , expectedStencil : 2 } ,
417+ { depthFailOp : 'increment-wrap' , initialStencil : 0xff , expectedStencil : 0 } ,
418+ { depthFailOp : 'decrement-clamp' , initialStencil : 1 , expectedStencil : 0 } ,
419+ { depthFailOp : 'decrement-clamp' , initialStencil : 0 , expectedStencil : 0 } ,
420+ { depthFailOp : 'decrement-wrap' , initialStencil : 2 , expectedStencil : 1 } ,
421+ { depthFailOp : 'decrement-wrap' , initialStencil : 1 , expectedStencil : 0 } ,
422+ { depthFailOp : 'decrement-wrap' , initialStencil : 0 , expectedStencil : 0xff } ,
423+ ] as const )
424+ )
425+ . fn ( async t => {
426+ const { depthFailOp, initialStencil, expectedStencil } = t . params ;
427+
428+ const stencilState = {
429+ compare : 'always' ,
430+ failOp : 'keep' ,
431+ passOp : 'keep' ,
432+ depthFailOp,
433+ } as const ;
434+
435+ // Call checkStencilOperation function with enabling the depthTest to test that the depthFailOp
436+ // stencil operation works as expected.
437+ t . checkStencilOperation ( stencilState , initialStencil , expectedStencil , 'never' ) ;
441438 } ) ;
442439
443440g . test ( 'stencil_read_write_mask' )
0 commit comments