Bug 1912155 [wpt PR 47520] - WebNN: Define `MLContext::destroy` interface, a=testonly

Automatic update from web-platform-tests
WebNN: Define `MLContext::destroy` interface

This CL defines `MLContext::destroy` interface on blink side. It's
to destroy the `MLContext` explicitly to let it be lost.

`MLContext` retains weak references to all of the `MLBuffer`,
`MLGraph` and `MLGraphBuilder` instances, their Mojo pipes will be
disconnected and their pending promises will be rejected at the
same time as the `MLContext` is destroyed. Any calls rely on the
`MLContext` are not allowed and will throw errors.

This CL sets disconnection handler for `MLGraphBuilder` to reject
pending promise of creating `MLGraph`.

This CL removes the unnecessary `MLContext::CreateWebNNBuffer`
method, refactors `MLBuffer::ReadBufferImpl` method to create
the resolver inside and return the promise, refactors
`MLContext::CreateWebNNGraphBuilder` to record the created
`MLGraphBuilder` into `MLContext` and return it.

Bug: 348904836, 354025380
Change-Id: Ia660fe2f109a089187237da9d6a0285247f19eb9
Cq-Include-Trybots: luci.chromium.try​:win11-blink-rel
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5737474
Commit-Queue: Mingming1 Xu <mingming1.xu@intel.com>
Reviewed-by: Reilly Grant <reillyg@chromium.org>
Reviewed-by: ningxin hu <ningxin.hu@intel.com>
Reviewed-by: Rafael Cintron <rafael.cintron@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#1338851}

--

wpt-commits: 2d8dac31b619e8941e383a5a68d6dfedd65b2d0b
wpt-pr: 47520
This commit is contained in:
mingmingtasd 2024-08-08 22:43:40 +00:00 коммит произвёл moz-wptsync-bot
Родитель e36b530018
Коммит 48b733f002
1 изменённых файлов: 150 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,150 @@
// META: timeout=long
// META: title=validation tests for WebNN API MLContext::destroy()
// META: global=window,dedicatedworker
'use strict';
promise_test(async t => {
const context = await navigator.ml.createContext();
context.destroy();
await context.lost;
}, 'Context will be lost by destroyed.');
promise_test(async t => {
const context = await navigator.ml.createContext();
context.destroy();
context.destroy();
await context.lost;
}, 'Context can be destroyed twice.');
promise_test(async t => {
const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);
context.destroy();
assert_throws_dom('InvalidStateError', () => {
const operandType = {dataType: 'float32', dimensions: [1]};
builder.input('input', operandType);
});
}, 'Destroyed context can not build operator.');
promise_test(async t => {
const context = await navigator.ml.createContext();
context.destroy();
assert_throws_dom('InvalidStateError', () => {
new MLGraphBuilder(context);
});
}, 'Destroyed context can not create graph builder.');
promise_test(async t => {
const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);
const operandType = {dataType: 'float32', dimensions: [1]};
const input_operand = builder.input('input', operandType);
const const_operand = builder.constant(operandType, Float32Array.from([2]));
const output_operand = builder.mul(input_operand, const_operand);
context.destroy();
promise_rejects_dom(
t, 'InvalidStateError', builder.build({'output': output_operand}));
}, 'Destroyed context can not build graph.');
promise_test(async t => {
const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);
const operandType = {dataType: 'float32', dimensions: [1]};
const input_operand = builder.input('input', operandType);
const const_operand = builder.constant(operandType, Float32Array.from([2]));
const output_operand = builder.mul(input_operand, const_operand);
const graph = await builder.build({'output': output_operand});
context.destroy();
let inputs = {'input': Float32Array.from([1])};
let outputs = {'output': new Float32Array(1)};
promise_rejects_dom(
t, 'InvalidStateError', context.compute(graph, inputs, outputs));
}, 'Destroyed context can not compute.');
promise_test(async t => {
const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);
const operandType = {dataType: 'float32', dimensions: [1]};
const lhsOperand = builder.input('lhs', operandType);
const rhsOperand = builder.input('rhs', operandType);
const graph =
await builder.build({'output': builder.sub(lhsOperand, rhsOperand)});
const lhsBuffer = await context.createBuffer(operandType);
const rhsBuffer = await context.createBuffer(operandType);
const dispatchOutputs = {'output': await context.createBuffer(operandType)};
context.destroy();
assert_throws_dom('InvalidStateError', () => {
context.dispatch(
graph, {
'lhs': lhsBuffer,
'rhs': rhsBuffer,
},
dispatchOutputs);
});
}, 'Destroyed context can not dispatch.');
promise_test(async t => {
const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);
const operandType = {dataType: 'float32', dimensions: [1]};
const lhsOperand = builder.input('lhs', operandType);
const rhsOperand = builder.input('rhs', operandType);
const graph =
await builder.build({'output': builder.sub(lhsOperand, rhsOperand)});
const lhsBuffer = await context.createBuffer(operandType);
const rhsBuffer = await context.createBuffer(operandType);
const dispatchOutputs = {'output': await context.createBuffer(operandType)};
context.dispatch(
graph, {
'lhs': lhsBuffer,
'rhs': rhsBuffer,
},
dispatchOutputs);
context.destroy();
}, 'Executing dispatch() before context destroyed is OK.');
promise_test(async t => {
const context = await navigator.ml.createContext();
context.destroy();
promise_rejects_dom(
t, 'InvalidStateError',
context.createBuffer({dataType: 'float32', dimensions: [1]}));
}, 'Destroyed context can not create buffer.');
promise_test(async t => {
const context = await navigator.ml.createContext();
const buffer =
await context.createBuffer({dataType: 'float32', dimensions: [1]});
context.destroy();
promise_rejects_dom(t, 'InvalidStateError', context.readBuffer(buffer));
}, 'Destroyed context can not read buffer.');
promise_test(async t => {
const context = await navigator.ml.createContext();
const buffer =
await context.createBuffer({dataType: 'float32', dimensions: [1]});
let promise = context.readBuffer(buffer);
context.destroy();
promise_rejects_dom(t, 'InvalidStateError', promise);
}, 'Pending promise of readbuffer() will be rejected immediately when context is destroyed.');
promise_test(async t => {
const context = await navigator.ml.createContext();
// Destroying another context doesn't impact the first context.
const another_context = await navigator.ml.createContext();
another_context.destroy();
const buffer =
await context.createBuffer({dataType: 'float32', dimensions: [1]});
let arrayBuffer = new ArrayBuffer(4);
context.destroy();
assert_throws_dom('InvalidStateError', () => {
context.writeBuffer(buffer, new Uint8Array(arrayBuffer));
});
}, 'Destroyed context can not write buffer.');