From 089bc9c7d8a39582900dd5450805dec29e1a09aa Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:13:07 +1000 Subject: [PATCH] tidy(ui): abstract worker logic to module --- .../controlLayers/konva/CanvasManager.ts | 42 +------------ .../controlLayers/konva/CanvasTransformer.ts | 2 +- .../controlLayers/konva/CanvasWorkerModule.ts | 61 +++++++++++++++++++ 3 files changed, 65 insertions(+), 40 deletions(-) create mode 100644 invokeai/frontend/web/src/features/controlLayers/konva/CanvasWorkerModule.ts diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts index 73c4d03d13..6a083f05ca 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts @@ -4,15 +4,14 @@ import type { AppStore } from 'app/store/store'; import type { SerializableObject } from 'common/types'; import { CanvasFilter } from 'features/controlLayers/konva/CanvasFilter'; import { CanvasStageModule } from 'features/controlLayers/konva/CanvasStageModule'; +import { CanvasWorkerModule } from 'features/controlLayers/konva/CanvasWorkerModule.js'; import { canvasToBlob, canvasToImageData, getImageDataTransparency, getPrefixedId, - nanoid, previewBlob, } from 'features/controlLayers/konva/util'; -import type { Extents, ExtentsResult, GetBboxTask, WorkerLogMessage } from 'features/controlLayers/konva/worker'; import type { CanvasV2State, GenerationMode, Rect } from 'features/controlLayers/store/types'; import type Konva from 'konva'; import { LRUCache } from 'lru-cache'; @@ -48,6 +47,7 @@ export class CanvasManager { background: CanvasBackground; filter: CanvasFilter; stage: CanvasStageModule; + worker: CanvasWorkerModule; log: Logger; socket: AppSocket; @@ -61,9 +61,6 @@ export class CanvasManager { canvasCache = new LRUCache({ max: 32 }); generationModeCache = new LRUCache({ max: 100 }); - _worker: Worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module', name: 'worker' }); - _tasks: Map void }> = new Map(); - constructor(stage: Konva.Stage, container: HTMLDivElement, store: AppStore, socket: AppSocket) { this.id = getPrefixedId(this.type); this.path = [this.id]; @@ -85,6 +82,7 @@ export class CanvasManager { }); this.stage = new CanvasStageModule(stage, container, this); + this.worker = new CanvasWorkerModule(this); this.preview = new CanvasPreview(this); this.stage.addLayer(this.preview.getLayer()); @@ -94,30 +92,6 @@ export class CanvasManager { this.filter = new CanvasFilter(this); - this._worker.onmessage = (event: MessageEvent) => { - const { type, data } = event.data; - if (type === 'log') { - if (data.ctx) { - this.log[data.level](data.ctx, data.message); - } else { - this.log[data.level](data.message); - } - } else if (type === 'extents') { - const task = this._tasks.get(data.id); - if (!task) { - return; - } - task.onComplete(data.extents); - this._tasks.delete(data.id); - } - }; - this._worker.onerror = (event) => { - this.log.error({ message: event.message }, 'Worker error'); - }; - this._worker.onmessageerror = () => { - this.log.error('Worker message error'); - }; - this.stateApi.$transformingEntity.set(null); this.stateApi.$toolState.set(this.stateApi.getToolState()); this.stateApi.$selectedEntityIdentifier.set(this.stateApi.getState().selectedEntityIdentifier); @@ -134,16 +108,6 @@ export class CanvasManager { this._isDebugging = false; } - requestBbox(data: Omit, onComplete: (extents: Extents | null) => void) { - const id = nanoid(); - const task: GetBboxTask = { - type: 'get_bbox', - data: { ...data, id }, - }; - this._tasks.set(id, { task, onComplete }); - this._worker.postMessage(task, [data.buffer]); - } - arrangeEntities() { let zIndex = 0; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasTransformer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasTransformer.ts index 9ea6b5ee24..6d8494beca 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasTransformer.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasTransformer.ts @@ -651,7 +651,7 @@ export class CanvasTransformer { // We have eraser strokes - we must calculate the bbox using pixel data const canvas = this.parent.renderer.getCanvas(undefined, { opacity: 1 }); const imageData = canvasToImageData(canvas); - this.manager.requestBbox( + this.manager.worker.requestBbox( { buffer: imageData.data.buffer, width: imageData.width, height: imageData.height }, (extents) => { if (extents) { diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasWorkerModule.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasWorkerModule.ts new file mode 100644 index 0000000000..9d61518be8 --- /dev/null +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasWorkerModule.ts @@ -0,0 +1,61 @@ +import type { SerializableObject } from 'common/types'; +import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; +import { getPrefixedId } from 'features/controlLayers/konva/util'; +import type { Extents, ExtentsResult, GetBboxTask, WorkerLogMessage } from 'features/controlLayers/konva/worker'; +import type { Logger } from 'roarr'; + +export class CanvasWorkerModule { + id: string; + path: string[]; + log: Logger; + manager: CanvasManager; + + worker: Worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module', name: 'worker' }); + tasks: Map void }> = new Map(); + + constructor(manager: CanvasManager) { + this.id = getPrefixedId('worker'); + this.manager = manager; + this.path = this.manager.path.concat(this.id); + this.log = this.manager.buildLogger(this.getLoggingContext); + this.log.debug('Creating canvas worker'); + + this.worker.onmessage = (event: MessageEvent) => { + const { type, data } = event.data; + if (type === 'log') { + if (data.ctx) { + this.log[data.level](data.ctx, data.message); + } else { + this.log[data.level](data.message); + } + } else if (type === 'extents') { + const task = this.tasks.get(data.id); + if (!task) { + return; + } + task.onComplete(data.extents); + this.tasks.delete(data.id); + } + }; + this.worker.onerror = (event) => { + this.log.error({ message: event.message }, 'Worker error'); + }; + this.worker.onmessageerror = () => { + this.log.error('Worker message error'); + }; + } + + requestBbox(data: Omit, onComplete: (extents: Extents | null) => void) { + const id = getPrefixedId('bbox_calculation'); + const task: GetBboxTask = { + type: 'get_bbox', + data: { ...data, id }, + }; + this.tasks.set(id, { task, onComplete }); + this.worker.postMessage(task, [data.buffer]); + } + + getLoggingContext = (): SerializableObject => { + return { ...this.manager.getLoggingContext(), path: this.path.join('.') }; + }; +}