@@ -433,7 +433,7 @@ fn main(
433
433
/**
434
434
* Checks bitwise ops results from a fragment shader.
435
435
*
436
- * Avoids the last row and column to skip potential helper invocations.
436
+ * Avoids subgroups in last row or column to skip potential helper invocations.
437
437
* @param data Framebuffer output
438
438
* * component 0 is result
439
439
* * component 1 is generated subgroup id
@@ -453,26 +453,58 @@ function checkBitwiseFragment(
453
453
) : Error | undefined {
454
454
const { uintsPerRow, uintsPerTexel } = getUintsPerFramebuffer ( format , width , height ) ;
455
455
456
- // Iteration skips last row and column to avoid helper invocations because it is not
457
- // guaranteed whether or not they participate in the subgroup operation.
456
+ // Determine if the subgroup should be included in the checks.
457
+ const inBounds = new Map < number , boolean > ( ) ;
458
+ for ( let row = 0 ; row < height ; row ++ ) {
459
+ for ( let col = 0 ; col < width ; col ++ ) {
460
+ const offset = uintsPerRow * row + col * uintsPerTexel ;
461
+ const subgroup_id = data [ offset + 1 ] ;
462
+ if ( subgroup_id === 0 ) {
463
+ return new Error ( `Internal error: helper invocation at (${ col } , ${ row } )` ) ;
464
+ }
465
+
466
+ let ok = inBounds . get ( subgroup_id ) ?? true ;
467
+ ok = ok && row !== height - 1 && col !== width - 1 ;
468
+ inBounds . set ( subgroup_id , ok ) ;
469
+ }
470
+ }
471
+
472
+ let anyInBounds = false ;
473
+ for ( const [ _ , value ] of inBounds ) {
474
+ const ok = Boolean ( value ) ;
475
+ anyInBounds = anyInBounds || ok ;
476
+ }
477
+ if ( ! anyInBounds ) {
478
+ // This variant would not reliably test behavior.
479
+ return undefined ;
480
+ }
481
+
482
+ // Iteration skips subgroups in the last row or column to avoid helper
483
+ // invocations because it is not guaranteed whether or not they participate
484
+ // in the subgroup operation.
458
485
const expected = new Map < number , number > ( ) ;
459
- for ( let row = 0 ; row < height - 1 ; row ++ ) {
460
- for ( let col = 0 ; col < width - 1 ; col ++ ) {
486
+ for ( let row = 0 ; row < height ; row ++ ) {
487
+ for ( let col = 0 ; col < width ; col ++ ) {
461
488
const offset = uintsPerRow * row + col * uintsPerTexel ;
462
489
const subgroup_id = data [ offset + 1 ] ;
463
490
464
491
if ( subgroup_id === 0 ) {
465
492
return new Error ( `Internal error: helper invocation at (${ col } , ${ row } )` ) ;
466
493
}
467
494
495
+ const subgroupInBounds = inBounds . get ( subgroup_id ) ?? true ;
496
+ if ( ! subgroupInBounds ) {
497
+ continue ;
498
+ }
499
+
468
500
let v = expected . get ( subgroup_id ) ?? identity ( op ) ;
469
501
v = bitwise ( op , v , input [ row * width + col ] ) ;
470
502
expected . set ( subgroup_id , v ) ;
471
503
}
472
504
}
473
505
474
- for ( let row = 0 ; row < height - 1 ; row ++ ) {
475
- for ( let col = 0 ; col < width - 1 ; col ++ ) {
506
+ for ( let row = 0 ; row < height ; row ++ ) {
507
+ for ( let col = 0 ; col < width ; col ++ ) {
476
508
const offset = uintsPerRow * row + col * uintsPerTexel ;
477
509
const res = data [ offset ] ;
478
510
const subgroup_id = data [ offset + 1 ] ;
@@ -482,6 +514,11 @@ function checkBitwiseFragment(
482
514
continue ;
483
515
}
484
516
517
+ const subgroupInBounds = inBounds . get ( subgroup_id ) ?? true ;
518
+ if ( ! subgroupInBounds ) {
519
+ continue ;
520
+ }
521
+
485
522
const expected_v = expected . get ( subgroup_id ) ?? 0 ;
486
523
if ( expected_v !== res ) {
487
524
return new Error ( `Row ${ row } , col ${ col } : incorrect results:
@@ -509,6 +546,14 @@ g.test('fragment,all_active')
509
546
} )
510
547
. fn ( async t => {
511
548
const numInputs = t . params . size [ 0 ] * t . params . size [ 1 ] ;
549
+
550
+ interface SubgroupLimits extends GPUSupportedLimits {
551
+ minSubgroupSize : number ;
552
+ }
553
+ const { minSubgroupSize } = t . device . limits as SubgroupLimits ;
554
+ const innerTexels = ( t . params . size [ 0 ] - 1 ) * ( t . params . size [ 1 ] - 1 ) ;
555
+ t . skipIf ( innerTexels < minSubgroupSize , 'Too few texels to be reliable' ) ;
556
+
512
557
const inputData = generateInputData ( t . params . case , numInputs , identity ( t . params . op ) ) ;
513
558
514
559
const ident = identity ( t . params . op ) === 0 ? '0' : '0xffffffff' ;
0 commit comments