fix(studio): a repair lands under the brush with no pill over it, and a browser with no device is not asked for one
This commit is contained in:
@@ -1050,7 +1050,12 @@ export function Workspace() {
|
||||
if (!engine || !previewBytes || shooting) return;
|
||||
const token = ++renderToken.current;
|
||||
const timer = setTimeout(async () => {
|
||||
setBusy(t('act.rendering'));
|
||||
// No spinner for this one, deliberately. The render is the page keeping up
|
||||
// with the reader — the brush's own spots are already drawn on the layer
|
||||
// above the photo, so the repair arriving under them a moment later is the
|
||||
// photo catching up and not a thing being waited for. A pill saying so was
|
||||
// read as the studio doing something to the frame (an export, a second
|
||||
// copy), and it stayed up through a HEAL long enough to be noticed.
|
||||
try {
|
||||
// The geometry is the frame's own; only the recipe differs between the
|
||||
// render and the compare copy, so the two can never drift apart.
|
||||
|
||||
@@ -71,16 +71,32 @@ async function warmsUp(ort: typeof Ort, session: Ort.InferenceSession): Promise<
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the browser has a device at all. `requestAdapter` answers for the
|
||||
// browser and not for this graph — an adapter is no promise the model runs on
|
||||
// it, the trial below is what settles that — but a *null* answer is a promise
|
||||
// it does not, and the attempt it saves is not nothing: a `create` that cannot
|
||||
// have a device still opens a session and tears it down (measured: 0.4s off the
|
||||
// first repair, and one backend fewer built on the way to the one that lasts).
|
||||
async function hasDevice(): Promise<boolean> {
|
||||
try {
|
||||
return Boolean(await navigator.gpu?.requestAdapter());
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// WebGPU first, the processor as the answer to every way that can fail: no
|
||||
// adapter, no `shader-f16` needed here but an op the provider never
|
||||
// implemented, a driver that opens a session and dies on the first dispatch.
|
||||
async function openSession(ort: typeof Ort): Promise<Ort.InferenceSession> {
|
||||
try {
|
||||
const gpu = await ort.InferenceSession.create(MODEL_URL, { executionProviders: ['webgpu'] });
|
||||
if (await warmsUp(ort, gpu)) return gpu;
|
||||
await gpu.release();
|
||||
} catch {
|
||||
// Whatever went wrong, the wasm provider is the fallback and not a failure.
|
||||
if (await hasDevice()) {
|
||||
try {
|
||||
const gpu = await ort.InferenceSession.create(MODEL_URL, { executionProviders: ['webgpu'] });
|
||||
if (await warmsUp(ort, gpu)) return gpu;
|
||||
await gpu.release();
|
||||
} catch {
|
||||
// Whatever went wrong, the wasm provider is the fallback and not a failure.
|
||||
}
|
||||
}
|
||||
return ort.InferenceSession.create(MODEL_URL, { executionProviders: ['wasm'] });
|
||||
}
|
||||
|
||||
@@ -28,9 +28,6 @@ export const en: Dict = {
|
||||
'act.reset': 'RESET',
|
||||
'act.export': 'EXPORT',
|
||||
'act.exporting': 'Exporting…',
|
||||
// The stage's own re-render behind a brush stroke or a knob: no file is being
|
||||
// written anywhere, and "Exporting…" over a HEAL was read as exactly that.
|
||||
'act.rendering': 'Rendering…',
|
||||
'act.upscaling': 'Upscaling the photo {done}/{total}…',
|
||||
'act.cancel': 'Cancel',
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ export const vi = {
|
||||
'act.reset': 'ĐẶT LẠI',
|
||||
'act.export': 'XUẤT ẢNH',
|
||||
'act.exporting': 'Đang xuất…',
|
||||
'act.rendering': 'Đang dựng ảnh…',
|
||||
'act.upscaling': 'Đang phóng to ảnh {done}/{total}…',
|
||||
'act.cancel': 'Huỷ',
|
||||
|
||||
|
||||
Reference in New Issue
Block a user