serialization.spec.ts (14178B)
1 export const description = `Unit tests for data cache serialization`; 2 3 import { getIsBuildingDataCache, setIsBuildingDataCache } from '../common/framework/data_cache.js'; 4 import { makeTestGroup } from '../common/internal/test_group.js'; 5 import { objectEquals } from '../common/util/util.js'; 6 import { 7 deserializeExpectation, 8 serializeExpectation, 9 } from '../webgpu/shader/execution/expression/case_cache.js'; 10 import BinaryStream from '../webgpu/util/binary_stream.js'; 11 import { 12 anyOf, 13 deserializeComparator, 14 serializeComparator, 15 skipUndefined, 16 } from '../webgpu/util/compare.js'; 17 import { kValue } from '../webgpu/util/constants.js'; 18 import { 19 abstractFloat, 20 abstractInt, 21 bool, 22 deserializeValue, 23 f16, 24 f32, 25 i16, 26 i32, 27 i8, 28 serializeValue, 29 toMatrix, 30 u16, 31 u32, 32 u8, 33 vec2, 34 vec3, 35 vec4, 36 } from '../webgpu/util/conversion.js'; 37 import { deserializeFPInterval, FP, serializeFPInterval } from '../webgpu/util/floating_point.js'; 38 39 import { UnitTest } from './unit_test.js'; 40 41 export const g = makeTestGroup(UnitTest); 42 43 g.test('value').fn(t => { 44 for (const value of [ 45 u32(kValue.u32.min + 0), 46 u32(kValue.u32.min + 1), 47 u32(kValue.u32.min + 2), 48 u32(kValue.u32.max - 2), 49 u32(kValue.u32.max - 1), 50 u32(kValue.u32.max - 0), 51 52 u16(kValue.u16.min + 0), 53 u16(kValue.u16.min + 1), 54 u16(kValue.u16.min + 2), 55 u16(kValue.u16.max - 2), 56 u16(kValue.u16.max - 1), 57 u16(kValue.u16.max - 0), 58 59 u8(kValue.u8.min + 0), 60 u8(kValue.u8.min + 1), 61 u8(kValue.u8.min + 2), 62 u8(kValue.u8.max - 2), 63 u8(kValue.u8.max - 1), 64 u8(kValue.u8.max - 0), 65 66 abstractInt(kValue.i64.negative.min), 67 abstractInt(kValue.i64.negative.min + 1n), 68 abstractInt(kValue.i64.negative.min + 2n), 69 abstractInt(kValue.i64.negative.max - 2n), 70 abstractInt(kValue.i64.negative.max - 1n), 71 abstractInt(kValue.i64.positive.min), 72 abstractInt(kValue.i64.positive.min + 1n), 73 abstractInt(kValue.i64.positive.min + 2n), 74 abstractInt(kValue.i64.positive.max - 2n), 75 abstractInt(kValue.i64.positive.max - 1n), 76 abstractInt(kValue.i64.positive.max), 77 78 i32(kValue.i32.negative.min + 0), 79 i32(kValue.i32.negative.min + 1), 80 i32(kValue.i32.negative.min + 2), 81 i32(kValue.i32.negative.max - 2), 82 i32(kValue.i32.negative.max - 1), 83 i32(kValue.i32.positive.min - 0), 84 i32(kValue.i32.positive.min + 1), 85 i32(kValue.i32.positive.min + 2), 86 i32(kValue.i32.positive.max - 2), 87 i32(kValue.i32.positive.max - 1), 88 i32(kValue.i32.positive.max - 0), 89 90 i16(kValue.i16.negative.min + 0), 91 i16(kValue.i16.negative.min + 1), 92 i16(kValue.i16.negative.min + 2), 93 i16(kValue.i16.negative.max - 2), 94 i16(kValue.i16.negative.max - 1), 95 i16(kValue.i16.positive.min + 0), 96 i16(kValue.i16.positive.min + 1), 97 i16(kValue.i16.positive.min + 2), 98 i16(kValue.i16.positive.max - 2), 99 i16(kValue.i16.positive.max - 1), 100 i16(kValue.i16.positive.max - 0), 101 102 i8(kValue.i8.negative.min + 0), 103 i8(kValue.i8.negative.min + 1), 104 i8(kValue.i8.negative.min + 2), 105 i8(kValue.i8.negative.max - 2), 106 i8(kValue.i8.negative.max - 1), 107 i8(kValue.i8.positive.min + 0), 108 i8(kValue.i8.positive.min + 1), 109 i8(kValue.i8.positive.min + 2), 110 i8(kValue.i8.positive.max - 2), 111 i8(kValue.i8.positive.max - 1), 112 i8(kValue.i8.positive.max - 0), 113 114 abstractFloat(0), 115 abstractFloat(-0), 116 abstractFloat(1), 117 abstractFloat(-1), 118 abstractFloat(0.5), 119 abstractFloat(-0.5), 120 abstractFloat(kValue.f64.positive.max), 121 abstractFloat(kValue.f64.positive.min), 122 abstractFloat(kValue.f64.positive.subnormal.max), 123 abstractFloat(kValue.f64.positive.subnormal.min), 124 abstractFloat(kValue.f64.negative.subnormal.max), 125 abstractFloat(kValue.f64.negative.subnormal.min), 126 abstractFloat(kValue.f64.positive.infinity), 127 abstractFloat(kValue.f64.negative.infinity), 128 129 f32(0), 130 f32(-0), 131 f32(1), 132 f32(-1), 133 f32(0.5), 134 f32(-0.5), 135 f32(kValue.f32.positive.max), 136 f32(kValue.f32.positive.min), 137 f32(kValue.f32.positive.subnormal.max), 138 f32(kValue.f32.positive.subnormal.min), 139 f32(kValue.f32.negative.subnormal.max), 140 f32(kValue.f32.negative.subnormal.min), 141 f32(kValue.f32.positive.infinity), 142 f32(kValue.f32.negative.infinity), 143 144 f16(0), 145 f16(-0), 146 f16(1), 147 f16(-1), 148 f16(0.5), 149 f16(-0.5), 150 f16(kValue.f16.positive.max), 151 f16(kValue.f16.positive.min), 152 f16(kValue.f16.positive.subnormal.max), 153 f16(kValue.f16.positive.subnormal.min), 154 f16(kValue.f16.negative.subnormal.max), 155 f16(kValue.f16.negative.subnormal.min), 156 f16(kValue.f16.positive.infinity), 157 f16(kValue.f16.negative.infinity), 158 159 bool(true), 160 bool(false), 161 162 vec2(f32(1), f32(2)), 163 vec3(u32(1), u32(2), u32(3)), 164 vec4(bool(false), bool(true), bool(false), bool(true)), 165 166 toMatrix( 167 [ 168 [0.0, 1.0], 169 [2.0, 3.0], 170 ], 171 abstractFloat 172 ), 173 toMatrix( 174 [ 175 [0.0, 1.0], 176 [2.0, 3.0], 177 ], 178 f32 179 ), 180 toMatrix( 181 [ 182 [0.0, 1.0, 2.0], 183 [3.0, 4.0, 5.0], 184 ], 185 f16 186 ), 187 toMatrix( 188 [ 189 [0.0, 1.0, 2.0, 3.0], 190 [4.0, 5.0, 6.0, 7.0], 191 ], 192 abstractFloat 193 ), 194 toMatrix( 195 [ 196 [0.0, 1.0, 2.0, 3.0], 197 [4.0, 5.0, 6.0, 7.0], 198 ], 199 f32 200 ), 201 toMatrix( 202 [ 203 [0.0, 1.0], 204 [2.0, 3.0], 205 [4.0, 5.0], 206 ], 207 f16 208 ), 209 toMatrix( 210 [ 211 [0.0, 1.0, 2.0], 212 [3.0, 4.0, 5.0], 213 [6.0, 7.0, 8.0], 214 ], 215 abstractFloat 216 ), 217 toMatrix( 218 [ 219 [0.0, 1.0, 2.0], 220 [3.0, 4.0, 5.0], 221 [6.0, 7.0, 8.0], 222 ], 223 f32 224 ), 225 toMatrix( 226 [ 227 [0.0, 1.0, 2.0, 3.0], 228 [4.0, 5.0, 6.0, 7.0], 229 [8.0, 9.0, 10.0, 11.0], 230 ], 231 f16 232 ), 233 toMatrix( 234 [ 235 [0.0, 1.0], 236 [2.0, 3.0], 237 [4.0, 5.0], 238 [6.0, 7.0], 239 ], 240 abstractFloat 241 ), 242 toMatrix( 243 [ 244 [0.0, 1.0], 245 [2.0, 3.0], 246 [4.0, 5.0], 247 [6.0, 7.0], 248 ], 249 f32 250 ), 251 toMatrix( 252 [ 253 [0.0, 1.0, 2.0], 254 [3.0, 4.0, 5.0], 255 [6.0, 7.0, 8.0], 256 [9.0, 10.0, 11.0], 257 ], 258 f16 259 ), 260 toMatrix( 261 [ 262 [0.0, 1.0, 2.0, 3.0], 263 [4.0, 5.0, 6.0, 7.0], 264 [8.0, 9.0, 10.0, 11.0], 265 [12.0, 13.0, 14.0, 15.0], 266 ], 267 abstractFloat 268 ), 269 toMatrix( 270 [ 271 [0.0, 1.0, 2.0, 3.0], 272 [4.0, 5.0, 6.0, 7.0], 273 [8.0, 9.0, 10.0, 11.0], 274 [12.0, 13.0, 14.0, 15.0], 275 ], 276 f32 277 ), 278 ]) { 279 const s = new BinaryStream(new Uint8Array(1024).buffer); 280 serializeValue(s, value); 281 const d = new BinaryStream(s.buffer().buffer); 282 const deserialized = deserializeValue(d); 283 t.expect( 284 objectEquals(value, deserialized), 285 `${value.type} ${value} -> serialize -> deserialize -> ${deserialized} 286 buffer: ${s.buffer()}` 287 ); 288 } 289 }); 290 291 g.test('fpinterval_f32').fn(t => { 292 for (const interval of [ 293 FP.f32.toInterval(0), 294 FP.f32.toInterval(-0), 295 FP.f32.toInterval(1), 296 FP.f32.toInterval(-1), 297 FP.f32.toInterval(0.5), 298 FP.f32.toInterval(-0.5), 299 FP.f32.toInterval(kValue.f32.positive.max), 300 FP.f32.toInterval(kValue.f32.positive.min), 301 FP.f32.toInterval(kValue.f32.positive.subnormal.max), 302 FP.f32.toInterval(kValue.f32.positive.subnormal.min), 303 FP.f32.toInterval(kValue.f32.negative.subnormal.max), 304 FP.f32.toInterval(kValue.f32.negative.subnormal.min), 305 FP.f32.toInterval(kValue.f32.positive.infinity), 306 FP.f32.toInterval(kValue.f32.negative.infinity), 307 308 FP.f32.toInterval([-0, 0]), 309 FP.f32.toInterval([-1, 1]), 310 FP.f32.toInterval([-0.5, 0.5]), 311 FP.f32.toInterval([kValue.f32.positive.min, kValue.f32.positive.max]), 312 FP.f32.toInterval([kValue.f32.positive.subnormal.min, kValue.f32.positive.subnormal.max]), 313 FP.f32.toInterval([kValue.f32.negative.subnormal.min, kValue.f32.negative.subnormal.max]), 314 FP.f32.toInterval([kValue.f32.negative.infinity, kValue.f32.positive.infinity]), 315 ]) { 316 const s = new BinaryStream(new Uint8Array(1024).buffer); 317 serializeFPInterval(s, interval); 318 const d = new BinaryStream(s.buffer().buffer); 319 const deserialized = deserializeFPInterval(d); 320 t.expect( 321 objectEquals(interval, deserialized), 322 `interval ${interval} -> serialize -> deserialize -> ${deserialized}` 323 ); 324 } 325 }); 326 327 g.test('fpinterval_f16').fn(t => { 328 for (const interval of [ 329 FP.f16.toInterval(0), 330 FP.f16.toInterval(-0), 331 FP.f16.toInterval(1), 332 FP.f16.toInterval(-1), 333 FP.f16.toInterval(0.5), 334 FP.f16.toInterval(-0.5), 335 FP.f16.toInterval(kValue.f16.positive.max), 336 FP.f16.toInterval(kValue.f16.positive.min), 337 FP.f16.toInterval(kValue.f16.positive.subnormal.max), 338 FP.f16.toInterval(kValue.f16.positive.subnormal.min), 339 FP.f16.toInterval(kValue.f16.negative.subnormal.max), 340 FP.f16.toInterval(kValue.f16.negative.subnormal.min), 341 FP.f16.toInterval(kValue.f16.positive.infinity), 342 FP.f16.toInterval(kValue.f16.negative.infinity), 343 344 FP.f16.toInterval([-0, 0]), 345 FP.f16.toInterval([-1, 1]), 346 FP.f16.toInterval([-0.5, 0.5]), 347 FP.f16.toInterval([kValue.f16.positive.min, kValue.f16.positive.max]), 348 FP.f16.toInterval([kValue.f16.positive.subnormal.min, kValue.f16.positive.subnormal.max]), 349 FP.f16.toInterval([kValue.f16.negative.subnormal.min, kValue.f16.negative.subnormal.max]), 350 FP.f16.toInterval([kValue.f16.negative.infinity, kValue.f16.positive.infinity]), 351 ]) { 352 const s = new BinaryStream(new Uint8Array(1024).buffer); 353 serializeFPInterval(s, interval); 354 const d = new BinaryStream(s.buffer().buffer); 355 const deserialized = deserializeFPInterval(d); 356 t.expect( 357 objectEquals(interval, deserialized), 358 `interval ${interval} -> serialize -> deserialize -> ${deserialized}` 359 ); 360 } 361 }); 362 363 g.test('fpinterval_abstract').fn(t => { 364 for (const interval of [ 365 FP.abstract.toInterval(0), 366 FP.abstract.toInterval(-0), 367 FP.abstract.toInterval(1), 368 FP.abstract.toInterval(-1), 369 FP.abstract.toInterval(0.5), 370 FP.abstract.toInterval(-0.5), 371 FP.abstract.toInterval(kValue.f64.positive.max), 372 FP.abstract.toInterval(kValue.f64.positive.min), 373 FP.abstract.toInterval(kValue.f64.positive.subnormal.max), 374 FP.abstract.toInterval(kValue.f64.positive.subnormal.min), 375 FP.abstract.toInterval(kValue.f64.negative.subnormal.max), 376 FP.abstract.toInterval(kValue.f64.negative.subnormal.min), 377 FP.abstract.toInterval(kValue.f64.positive.infinity), 378 FP.abstract.toInterval(kValue.f64.negative.infinity), 379 380 FP.abstract.toInterval([-0, 0]), 381 FP.abstract.toInterval([-1, 1]), 382 FP.abstract.toInterval([-0.5, 0.5]), 383 FP.abstract.toInterval([kValue.f64.positive.min, kValue.f64.positive.max]), 384 FP.abstract.toInterval([kValue.f64.positive.subnormal.min, kValue.f64.positive.subnormal.max]), 385 FP.abstract.toInterval([kValue.f64.negative.subnormal.min, kValue.f64.negative.subnormal.max]), 386 FP.abstract.toInterval([kValue.f64.negative.infinity, kValue.f64.positive.infinity]), 387 ]) { 388 const s = new BinaryStream(new Uint8Array(1024).buffer); 389 serializeFPInterval(s, interval); 390 const d = new BinaryStream(s.buffer().buffer); 391 const deserialized = deserializeFPInterval(d); 392 t.expect( 393 objectEquals(interval, deserialized), 394 `interval ${interval} -> serialize -> deserialize -> ${deserialized}` 395 ); 396 } 397 }); 398 399 g.test('expression_expectation').fn(t => { 400 for (const expectation of [ 401 // Value 402 f32(123), 403 vec2(f32(1), f32(2)), 404 // Interval 405 FP.f32.toInterval([-0.5, 0.5]), 406 FP.f32.toInterval([kValue.f32.positive.min, kValue.f32.positive.max]), 407 // Intervals 408 [FP.f32.toInterval([-8.0, 0.5]), FP.f32.toInterval([2.0, 4.0])], 409 ]) { 410 const s = new BinaryStream(new Uint8Array(1024).buffer); 411 serializeExpectation(s, expectation); 412 const d = new BinaryStream(s.buffer().buffer); 413 const deserialized = deserializeExpectation(d); 414 t.expect( 415 objectEquals(expectation, deserialized), 416 `expectation ${expectation} -> serialize -> deserialize -> ${deserialized}` 417 ); 418 } 419 }); 420 421 /** 422 * Temporarily enabled building of the data cache. 423 * Required for Comparators to serialize. 424 */ 425 function enableBuildingDataCache(f: () => void) { 426 const wasBuildingDataCache = getIsBuildingDataCache(); 427 setIsBuildingDataCache(true); 428 f(); 429 setIsBuildingDataCache(wasBuildingDataCache); 430 } 431 432 g.test('anyOf').fn(t => { 433 enableBuildingDataCache(() => { 434 for (const c of [ 435 { 436 comparator: anyOf(i32(123)), 437 testCases: [f32(0), f32(10), f32(122), f32(123), f32(124), f32(200)], 438 }, 439 ]) { 440 const s = new BinaryStream(new Uint8Array(1024).buffer); 441 serializeComparator(s, c.comparator); 442 const d = new BinaryStream(s.buffer().buffer); 443 const deserialized = deserializeComparator(d); 444 for (const val of c.testCases) { 445 const got = deserialized.compare(val); 446 const expect = c.comparator.compare(val); 447 t.expect( 448 got.matched === expect.matched, 449 `comparator(${val}): got: ${expect.matched}, expect: ${got.matched}` 450 ); 451 } 452 } 453 }); 454 }); 455 456 g.test('skipUndefined').fn(t => { 457 enableBuildingDataCache(() => { 458 for (const c of [ 459 { 460 comparator: skipUndefined(i32(123)), 461 testCases: [f32(0), f32(10), f32(122), f32(123), f32(124), f32(200)], 462 }, 463 { 464 comparator: skipUndefined(undefined), 465 testCases: [f32(0), f32(10), f32(122), f32(123), f32(124), f32(200)], 466 }, 467 ]) { 468 const s = new BinaryStream(new Uint8Array(1024).buffer); 469 serializeComparator(s, c.comparator); 470 const d = new BinaryStream(s.buffer().buffer); 471 const deserialized = deserializeComparator(d); 472 for (const val of c.testCases) { 473 const got = deserialized.compare(val); 474 const expect = c.comparator.compare(val); 475 t.expect( 476 got.matched === expect.matched, 477 `comparator(${val}): got: ${expect.matched}, expect: ${got.matched}` 478 ); 479 } 480 } 481 }); 482 });