byob_readtensor.https.any.js (6284B)
1 // META: title=test WebNN API tensor operations 2 // META: global=window,worker 3 // META: variant=?cpu 4 // META: variant=?gpu 5 // META: variant=?npu 6 // META: script=../resources/utils_validation.js 7 // META: script=../resources/utils.js 8 // META: timeout=long 9 10 'use strict'; 11 12 // Skip tests if WebNN is unimplemented. 13 promise_setup(async () => { 14 assert_implements(navigator.ml, 'missing navigator.ml'); 15 }); 16 17 // https://www.w3.org/TR/webnn/#api-mltensor 18 19 const testContents = Uint32Array.from([0, 1, 2, 3, 4, 5, 6, 7]); 20 21 let mlContext; 22 let mlTensor; 23 promise_setup(async () => { 24 try { 25 mlContext = await navigator.ml.createContext(contextOptions); 26 } catch (e) { 27 throw new AssertionError( 28 `Unable to create context for ${variant} variant. ${e}`); 29 } 30 31 try { 32 mlTensor = await mlContext.createTensor({ 33 dataType: 'int32', 34 shape: [2, 4], 35 readable: true, 36 writable: true, 37 }); 38 } catch (e) { 39 throw new AssertionError( 40 `Unable to create tensor for ${variant} variant. ${e}`); 41 } 42 43 mlContext.writeTensor(mlTensor, testContents); 44 }); 45 46 promise_test(async (t) => { 47 const arrayBuffer = new ArrayBuffer(testContents.byteLength - 4); 48 49 await promise_rejects_js( 50 t, TypeError, mlContext.readTensor(mlTensor, arrayBuffer)); 51 }, `readTensor() with an ArrayBuffer that is too small should reject`); 52 53 promise_test(async (t) => { 54 const typedArray = new Uint32Array(testContents.length - 1); 55 56 await promise_rejects_js( 57 t, TypeError, mlContext.readTensor(mlTensor, typedArray)); 58 }, `readTensor() with a TypedArray that is too small should reject`); 59 60 promise_test(async (t) => { 61 const arrayBuffer = new ArrayBuffer(testContents.byteLength); 62 const typedArray = new Uint32Array(arrayBuffer); 63 64 arrayBuffer.transfer(); 65 66 await promise_rejects_js( 67 t, TypeError, mlContext.readTensor(mlTensor, arrayBuffer)); 68 69 await promise_rejects_js( 70 t, TypeError, mlContext.readTensor(mlTensor, typedArray)); 71 }, `readTensor() with a detached ArrayBuffer should reject`); 72 73 promise_test(async (t) => { 74 const arrayBuffer = new ArrayBuffer(testContents.byteLength); 75 const typedArray = new Uint32Array(arrayBuffer); 76 77 const checks = Promise.all([ 78 promise_rejects_js( 79 t, TypeError, mlContext.readTensor(mlTensor, arrayBuffer)), 80 promise_rejects_js( 81 t, TypeError, mlContext.readTensor(mlTensor, typedArray)), 82 ]); 83 84 arrayBuffer.transfer(); 85 86 await checks; 87 }, `Detaching an ArrayBuffer while readTensor() is in progress should reject`); 88 89 promise_test(async () => { 90 const arrayBuffer = new ArrayBuffer(testContents.byteLength); 91 92 await mlContext.readTensor(mlTensor, arrayBuffer); 93 94 assert_array_equals(new Uint32Array(arrayBuffer), testContents); 95 }, `readTensor() with an ArrayBuffer`); 96 97 if ('SharedArrayBuffer' in globalThis) { 98 promise_test(async () => { 99 const sharedArrayBuffer = new SharedArrayBuffer(testContents.byteLength); 100 101 await mlContext.readTensor(mlTensor, sharedArrayBuffer); 102 103 assert_array_equals(new Uint32Array(sharedArrayBuffer), testContents); 104 }, `readTensor() with a SharedArrayBuffer`); 105 106 promise_test(async () => { 107 const sharedArrayBuffer = new SharedArrayBuffer(testContents.byteLength); 108 const typedArray = new Uint32Array(sharedArrayBuffer); 109 110 await mlContext.readTensor(mlTensor, typedArray); 111 112 assert_array_equals(typedArray, testContents); 113 }, `readTensor() with a typeArray from a SharedArrayBuffer`); 114 } 115 116 promise_test(async () => { 117 // Create a slightly larger ArrayBuffer and set up the TypedArray at an 118 // offset to make sure the MLTensor contents are written to the correct 119 // offset. 120 const arrayBuffer = new ArrayBuffer(testContents.byteLength + 4); 121 const typedArray = new Uint32Array(arrayBuffer, 4); 122 123 await mlContext.readTensor(mlTensor, typedArray); 124 125 assert_array_equals(typedArray, testContents); 126 }, `readTensor() with a TypedArray`); 127 128 promise_test(async () => { 129 const arrayBuffer = new ArrayBuffer(testContents.byteLength * 2); 130 131 await mlContext.readTensor(mlTensor, arrayBuffer); 132 133 assert_array_equals( 134 new Uint32Array(arrayBuffer).subarray(0, testContents.length), 135 testContents); 136 // The rest of the array should remain uninitialized. 137 assert_array_equals( 138 new Uint32Array(arrayBuffer) 139 .subarray(testContents.length, testContents.length * 2), 140 new Uint32Array(testContents.length)); 141 }, `readTensor() with a larger ArrayBuffer`); 142 143 promise_test(async () => { 144 // Create a slightly larger ArrayBuffer and set up the TypedArray at an 145 // offset to make sure the MLTensor contents are written to the correct 146 // offset. 147 const arrayBuffer = new ArrayBuffer(testContents.byteLength * 2 + 4); 148 const typedArray = new Uint32Array(arrayBuffer, 4); 149 150 await mlContext.readTensor(mlTensor, typedArray); 151 152 assert_array_equals( 153 typedArray.subarray(0, testContents.length), testContents); 154 // The rest of the array should remain uninitialized. 155 assert_array_equals( 156 typedArray.subarray(testContents.length, testContents.length * 2), 157 new Uint32Array(testContents.length)); 158 }, `readTensor() with a larger TypedArray`); 159 160 promise_test(async (t) => { 161 const tensor = await mlContext.createTensor({ 162 dataType: 'int32', 163 shape: [2, 2], 164 readable: true, 165 }); 166 const arrayBufferView = new Int32Array(2 * 2); 167 const arrayBuffer = arrayBufferView.buffer; 168 169 // Reading a destroyed MLTensor should reject. 170 tensor.destroy(); 171 172 await promise_rejects_dom( 173 t, 'InvalidStateError', mlContext.readTensor(tensor, arrayBuffer)); 174 await promise_rejects_dom( 175 t, 'InvalidStateError', mlContext.readTensor(tensor, arrayBufferView)); 176 }, `readTensor() rejects on a destroyed MLTensor`); 177 178 promise_test(async (t) => { 179 const tensor = await mlContext.createTensor({ 180 dataType: 'int32', 181 shape: [2, 2], 182 readable: true, 183 }); 184 const arrayBufferView = new Int32Array(2 * 2); 185 const arrayBuffer = arrayBufferView.buffer; 186 187 const checks = Promise.all([ 188 promise_rejects_dom( 189 t, 'InvalidStateError', mlContext.readTensor(tensor, arrayBuffer)), 190 promise_rejects_dom( 191 t, 'InvalidStateError', mlContext.readTensor(tensor, arrayBufferView)), 192 ]); 193 194 tensor.destroy(); 195 196 await checks; 197 }, `readTensor() rejects when the MLTensor is destroyed`);