From 255ad3d2adbf8b7020e95125066f5b3dcff40562 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:23:16 +1000 Subject: [PATCH] tidy(ui): abstract caching logic to module --- .../ControlLayersSettingsPopover.tsx | 2 +- .../controlLayers/konva/CanvasCacheModule.ts | 35 +++++++++++++++++++ .../controlLayers/konva/CanvasManager.ts | 34 +++++++----------- 3 files changed, 49 insertions(+), 22 deletions(-) create mode 100644 invokeai/frontend/web/src/features/controlLayers/konva/CanvasCacheModule.ts diff --git a/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersSettingsPopover.tsx b/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersSettingsPopover.tsx index 2d678b701a..7e1191d2f1 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersSettingsPopover.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersSettingsPopover.tsx @@ -35,7 +35,7 @@ const ControlLayersSettingsPopover = () => { [dispatch] ); const clearCaches = useCallback(() => { - canvasManager?.clearCaches(); + canvasManager?.cache.clearAll(); }, [canvasManager]); const calculateBboxes = useCallback(() => { if (!canvasManager) { diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasCacheModule.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasCacheModule.ts new file mode 100644 index 0000000000..c81bde7fd4 --- /dev/null +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasCacheModule.ts @@ -0,0 +1,35 @@ +import type { SerializableObject } from 'common/types'; +import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; +import { getPrefixedId } from 'features/controlLayers/konva/util'; +import type { GenerationMode } from 'features/controlLayers/store/types'; +import { LRUCache } from 'lru-cache'; +import type { Logger } from 'roarr'; + +export class CanvasCacheModule { + id: string; + path: string[]; + log: Logger; + manager: CanvasManager; + + imageNameCache = new LRUCache({ max: 100 }); + canvasElementCache = new LRUCache({ max: 32 }); + generationModeCache = new LRUCache({ max: 100 }); + + constructor(manager: CanvasManager) { + this.id = getPrefixedId('cache'); + this.manager = manager; + this.path = this.manager.path.concat(this.id); + this.log = this.manager.buildLogger(this.getLoggingContext); + this.log.debug('Creating canvas cache'); + } + + clearAll = () => { + this.canvasElementCache.clear(); + this.imageNameCache.clear(); + this.generationModeCache.clear(); + }; + + getLoggingContext = (): SerializableObject => { + return { ...this.manager.getLoggingContext(), path: this.path.join('.') }; + }; +} diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts index 6a083f05ca..9878c63276 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts @@ -2,6 +2,7 @@ import type { AppSocket } from 'app/hooks/useSocketIO'; import { logger } from 'app/logging/logger'; import type { AppStore } from 'app/store/store'; import type { SerializableObject } from 'common/types'; +import { CanvasCacheModule } from 'features/controlLayers/konva/CanvasCacheModule'; import { CanvasFilter } from 'features/controlLayers/konva/CanvasFilter'; import { CanvasStageModule } from 'features/controlLayers/konva/CanvasStageModule'; import { CanvasWorkerModule } from 'features/controlLayers/konva/CanvasWorkerModule.js'; @@ -14,7 +15,6 @@ import { } from 'features/controlLayers/konva/util'; import type { CanvasV2State, GenerationMode, Rect } from 'features/controlLayers/store/types'; import type Konva from 'konva'; -import { LRUCache } from 'lru-cache'; import { atom } from 'nanostores'; import type { Logger } from 'roarr'; import { getImageDTO, uploadImage } from 'services/api/endpoints/images'; @@ -48,6 +48,7 @@ export class CanvasManager { filter: CanvasFilter; stage: CanvasStageModule; worker: CanvasWorkerModule; + cache: CanvasCacheModule; log: Logger; socket: AppSocket; @@ -57,10 +58,6 @@ export class CanvasManager { isFirstRender: boolean = true; _isDebugging: boolean = false; - imageNameCache = new LRUCache({ max: 100 }); - canvasCache = new LRUCache({ max: 32 }); - generationModeCache = new LRUCache({ max: 100 }); - constructor(stage: Konva.Stage, container: HTMLDivElement, store: AppStore, socket: AppSocket) { this.id = getPrefixedId(this.type); this.path = [this.id]; @@ -83,6 +80,7 @@ export class CanvasManager { this.stage = new CanvasStageModule(stage, container, this); this.worker = new CanvasWorkerModule(this); + this.cache = new CanvasCacheModule(this); this.preview = new CanvasPreview(this); this.stage.addLayer(this.preview.getLayer()); @@ -404,12 +402,6 @@ export class CanvasManager { }; }; - clearCaches = () => { - this.canvasCache.clear(); - this.imageNameCache.clear(); - this.generationModeCache.clear(); - }; - getCompositeRasterLayerEntityIds = (): string[] => { const ids = []; for (const adapter of this.rasterLayerAdapters.values()) { @@ -432,7 +424,7 @@ export class CanvasManager { getCompositeRasterLayerCanvas = (rect: Rect): HTMLCanvasElement => { const hash = this.getCompositeRasterLayerHash({ rect }); - const cachedCanvas = this.canvasCache.get(hash); + const cachedCanvas = this.cache.canvasElementCache.get(hash); if (cachedCanvas) { this.log.trace({ rect }, 'Using cached composite inpaint mask canvas'); @@ -458,13 +450,13 @@ export class CanvasManager { const adapterCanvas = adapter.getCanvas(rect); ctx.drawImage(adapterCanvas, 0, 0); } - this.canvasCache.set(hash, canvas); + this.cache.canvasElementCache.set(hash, canvas); return canvas; }; getCompositeInpaintMaskCanvas = (rect: Rect): HTMLCanvasElement => { const hash = this.getCompositeInpaintMaskHash({ rect }); - const cachedCanvas = this.canvasCache.get(hash); + const cachedCanvas = this.cache.canvasElementCache.get(hash); if (cachedCanvas) { this.log.trace({ rect }, 'Using cached composite inpaint mask canvas'); @@ -490,7 +482,7 @@ export class CanvasManager { const adapterCanvas = adapter.getCanvas(rect); ctx.drawImage(adapterCanvas, 0, 0); } - this.canvasCache.set(hash, canvas); + this.cache.canvasElementCache.set(hash, canvas); return canvas; }; @@ -528,7 +520,7 @@ export class CanvasManager { let imageDTO: ImageDTO | null = null; const hash = this.getCompositeRasterLayerHash({ rect }); - const cachedImageName = this.imageNameCache.get(hash); + const cachedImageName = this.cache.imageNameCache.get(hash); if (cachedImageName) { imageDTO = await getImageDTO(cachedImageName); @@ -547,7 +539,7 @@ export class CanvasManager { } imageDTO = await uploadImage(blob, 'composite-raster-layer.png', 'general', true); - this.imageNameCache.set(hash, imageDTO.image_name); + this.cache.imageNameCache.set(hash, imageDTO.image_name); return imageDTO; }; @@ -555,7 +547,7 @@ export class CanvasManager { let imageDTO: ImageDTO | null = null; const hash = this.getCompositeInpaintMaskHash({ rect }); - const cachedImageName = this.imageNameCache.get(hash); + const cachedImageName = this.cache.imageNameCache.get(hash); if (cachedImageName) { imageDTO = await getImageDTO(cachedImageName); @@ -574,7 +566,7 @@ export class CanvasManager { } imageDTO = await uploadImage(blob, 'composite-inpaint-mask.png', 'general', true); - this.imageNameCache.set(hash, imageDTO.image_name); + this.cache.imageNameCache.set(hash, imageDTO.image_name); return imageDTO; }; @@ -584,7 +576,7 @@ export class CanvasManager { const compositeInpaintMaskHash = this.getCompositeInpaintMaskHash({ rect }); const compositeRasterLayerHash = this.getCompositeRasterLayerHash({ rect }); const hash = stableHash({ rect, compositeInpaintMaskHash, compositeRasterLayerHash }); - const cachedGenerationMode = this.generationModeCache.get(hash); + const cachedGenerationMode = this.cache.generationModeCache.get(hash); if (cachedGenerationMode) { this.log.trace({ rect, cachedGenerationMode }, 'Using cached generation mode'); @@ -612,7 +604,7 @@ export class CanvasManager { generationMode = 'inpaint'; } - this.generationModeCache.set(hash, generationMode); + this.cache.generationModeCache.set(hash, generationMode); return generationMode; }