@@ -8,7 +8,17 @@ const kSampleCases = [
88 { lhs : [ 1 , 2 , 3 , 4 ] , rhs : [ 4 , 3 , 2 , 1 ] } ,
99] as const ;
1010
11- const kWorkgroupSize = 64 ; // Same as in packed.wgsl
11+ const kWorkgroupSize = 64 ; // Must match packed.wgsl
12+
13+ type vec4i = readonly [ number , number , number , number ] ;
14+ // Pack four signed 8-bit components into a u32, low byte first.
15+ function pack4xI8 ( [ x , y , z , w ] : vec4i ) : number {
16+ // `&` operator applies sign extension to i32 before operating.
17+ // `>>> 0` converts the final i32 to u32.
18+ return (
19+ ( x & 0xff ) | ( ( y & 0xff ) << 8 ) | ( ( z & 0xff ) << 16 ) | ( ( w & 0xff ) << 24 )
20+ ) >>> 0 ;
21+ }
1222
1323const result = document . querySelector ( '#result' ) as HTMLElement ;
1424if (
2333 const device = await adapter ?. requestDevice ( ) ;
2434 quitIfWebGPUNotAvailableOrMissingFeatures ( adapter , device ) ;
2535
26- function createInputBuffer (
27- vectors : ReadonlyArray < readonly [ number , number , number , number ] >
28- ) {
29- // Pack four signed 8-bit components into each u32, low byte first.
30- // Masking preserves the two's-complement representation of negative values.
31- const packed = new Uint32Array (
32- vectors . map (
33- ( [ x , y , z , w ] ) =>
34- ( x & 0xff ) |
35- ( ( y & 0xff ) << 8 ) |
36- ( ( z & 0xff ) << 16 ) |
37- ( ( w & 0xff ) << 24 )
38- )
39- ) ;
36+ function createInputBuffer ( vectors : vec4i [ ] ) {
37+ const packed = new Uint32Array ( vectors . map ( pack4xI8 ) ) ;
4038 const buffer = device . createBuffer ( {
4139 size : packed . byteLength ,
4240 usage : GPUBufferUsage . STORAGE ,
9088 sample . lhs [ 1 ] * sample . rhs [ 1 ] +
9189 sample . lhs [ 2 ] * sample . rhs [ 2 ] +
9290 sample . lhs [ 3 ] * sample . rhs [ 3 ] ;
93- const lhs = sample . lhs . map ( ( x ) => x . toString ( ) . padStart ( 4 ) ) . join ( ', ' ) ;
94- const rhs = sample . rhs . map ( ( x ) => x . toString ( ) . padStart ( 4 ) ) . join ( ', ' ) ;
91+ const lhs = `[${ sample . lhs
92+ . map ( ( x ) => x . toString ( ) . padStart ( 4 ) )
93+ . join ( ', ' ) } ] (0x${ pack4xI8 ( sample . lhs ) . toString ( 16 ) . padStart ( 8 , '0' ) } )`;
94+ const rhs = `[${ sample . rhs
95+ . map ( ( x ) => x . toString ( ) . padStart ( 4 ) )
96+ . join ( ', ' ) } ] (0x${ pack4xI8 ( sample . rhs ) . toString ( 16 ) . padStart ( 8 , '0' ) } )`;
9597 const out = results [ i ] . toString ( ) . padStart ( 6 ) ;
9698 const exp = expected . toString ( ) . padStart ( 6 ) ;
97- result . textContent += `\ndot4I8Packed of [${ lhs } ] by [${ rhs } ] gave ${ out } (expecting ${ exp } )` ;
99+ result . textContent += `
100+
101+ WGSL dot4I8Packed of ${ lhs }
102+ by ${ rhs } gave ${ out } (JS gave ${ exp } )` ;
98103 }
99104}
0 commit comments