tidy(ui): abstract caching logic to module

This commit is contained in:
psychedelicious 2024-08-22 10:23:16 +10:00
parent 089bc9c7d8
commit 255ad3d2ad
3 changed files with 49 additions and 22 deletions

View File

@ -35,7 +35,7 @@ const ControlLayersSettingsPopover = () => {
[dispatch] [dispatch]
); );
const clearCaches = useCallback(() => { const clearCaches = useCallback(() => {
canvasManager?.clearCaches(); canvasManager?.cache.clearAll();
}, [canvasManager]); }, [canvasManager]);
const calculateBboxes = useCallback(() => { const calculateBboxes = useCallback(() => {
if (!canvasManager) { if (!canvasManager) {

View File

@ -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<string, string>({ max: 100 });
canvasElementCache = new LRUCache<string, HTMLCanvasElement>({ max: 32 });
generationModeCache = new LRUCache<string, GenerationMode>({ 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('.') };
};
}

View File

@ -2,6 +2,7 @@ import type { AppSocket } from 'app/hooks/useSocketIO';
import { logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import type { AppStore } from 'app/store/store'; import type { AppStore } from 'app/store/store';
import type { SerializableObject } from 'common/types'; import type { SerializableObject } from 'common/types';
import { CanvasCacheModule } from 'features/controlLayers/konva/CanvasCacheModule';
import { CanvasFilter } from 'features/controlLayers/konva/CanvasFilter'; import { CanvasFilter } from 'features/controlLayers/konva/CanvasFilter';
import { CanvasStageModule } from 'features/controlLayers/konva/CanvasStageModule'; import { CanvasStageModule } from 'features/controlLayers/konva/CanvasStageModule';
import { CanvasWorkerModule } from 'features/controlLayers/konva/CanvasWorkerModule.js'; import { CanvasWorkerModule } from 'features/controlLayers/konva/CanvasWorkerModule.js';
@ -14,7 +15,6 @@ import {
} from 'features/controlLayers/konva/util'; } from 'features/controlLayers/konva/util';
import type { CanvasV2State, GenerationMode, Rect } from 'features/controlLayers/store/types'; import type { CanvasV2State, GenerationMode, Rect } from 'features/controlLayers/store/types';
import type Konva from 'konva'; import type Konva from 'konva';
import { LRUCache } from 'lru-cache';
import { atom } from 'nanostores'; import { atom } from 'nanostores';
import type { Logger } from 'roarr'; import type { Logger } from 'roarr';
import { getImageDTO, uploadImage } from 'services/api/endpoints/images'; import { getImageDTO, uploadImage } from 'services/api/endpoints/images';
@ -48,6 +48,7 @@ export class CanvasManager {
filter: CanvasFilter; filter: CanvasFilter;
stage: CanvasStageModule; stage: CanvasStageModule;
worker: CanvasWorkerModule; worker: CanvasWorkerModule;
cache: CanvasCacheModule;
log: Logger; log: Logger;
socket: AppSocket; socket: AppSocket;
@ -57,10 +58,6 @@ export class CanvasManager {
isFirstRender: boolean = true; isFirstRender: boolean = true;
_isDebugging: boolean = false; _isDebugging: boolean = false;
imageNameCache = new LRUCache<string, string>({ max: 100 });
canvasCache = new LRUCache<string, HTMLCanvasElement>({ max: 32 });
generationModeCache = new LRUCache<string, GenerationMode>({ max: 100 });
constructor(stage: Konva.Stage, container: HTMLDivElement, store: AppStore, socket: AppSocket) { constructor(stage: Konva.Stage, container: HTMLDivElement, store: AppStore, socket: AppSocket) {
this.id = getPrefixedId(this.type); this.id = getPrefixedId(this.type);
this.path = [this.id]; this.path = [this.id];
@ -83,6 +80,7 @@ export class CanvasManager {
this.stage = new CanvasStageModule(stage, container, this); this.stage = new CanvasStageModule(stage, container, this);
this.worker = new CanvasWorkerModule(this); this.worker = new CanvasWorkerModule(this);
this.cache = new CanvasCacheModule(this);
this.preview = new CanvasPreview(this); this.preview = new CanvasPreview(this);
this.stage.addLayer(this.preview.getLayer()); 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[] => { getCompositeRasterLayerEntityIds = (): string[] => {
const ids = []; const ids = [];
for (const adapter of this.rasterLayerAdapters.values()) { for (const adapter of this.rasterLayerAdapters.values()) {
@ -432,7 +424,7 @@ export class CanvasManager {
getCompositeRasterLayerCanvas = (rect: Rect): HTMLCanvasElement => { getCompositeRasterLayerCanvas = (rect: Rect): HTMLCanvasElement => {
const hash = this.getCompositeRasterLayerHash({ rect }); const hash = this.getCompositeRasterLayerHash({ rect });
const cachedCanvas = this.canvasCache.get(hash); const cachedCanvas = this.cache.canvasElementCache.get(hash);
if (cachedCanvas) { if (cachedCanvas) {
this.log.trace({ rect }, 'Using cached composite inpaint mask canvas'); this.log.trace({ rect }, 'Using cached composite inpaint mask canvas');
@ -458,13 +450,13 @@ export class CanvasManager {
const adapterCanvas = adapter.getCanvas(rect); const adapterCanvas = adapter.getCanvas(rect);
ctx.drawImage(adapterCanvas, 0, 0); ctx.drawImage(adapterCanvas, 0, 0);
} }
this.canvasCache.set(hash, canvas); this.cache.canvasElementCache.set(hash, canvas);
return canvas; return canvas;
}; };
getCompositeInpaintMaskCanvas = (rect: Rect): HTMLCanvasElement => { getCompositeInpaintMaskCanvas = (rect: Rect): HTMLCanvasElement => {
const hash = this.getCompositeInpaintMaskHash({ rect }); const hash = this.getCompositeInpaintMaskHash({ rect });
const cachedCanvas = this.canvasCache.get(hash); const cachedCanvas = this.cache.canvasElementCache.get(hash);
if (cachedCanvas) { if (cachedCanvas) {
this.log.trace({ rect }, 'Using cached composite inpaint mask canvas'); this.log.trace({ rect }, 'Using cached composite inpaint mask canvas');
@ -490,7 +482,7 @@ export class CanvasManager {
const adapterCanvas = adapter.getCanvas(rect); const adapterCanvas = adapter.getCanvas(rect);
ctx.drawImage(adapterCanvas, 0, 0); ctx.drawImage(adapterCanvas, 0, 0);
} }
this.canvasCache.set(hash, canvas); this.cache.canvasElementCache.set(hash, canvas);
return canvas; return canvas;
}; };
@ -528,7 +520,7 @@ export class CanvasManager {
let imageDTO: ImageDTO | null = null; let imageDTO: ImageDTO | null = null;
const hash = this.getCompositeRasterLayerHash({ rect }); const hash = this.getCompositeRasterLayerHash({ rect });
const cachedImageName = this.imageNameCache.get(hash); const cachedImageName = this.cache.imageNameCache.get(hash);
if (cachedImageName) { if (cachedImageName) {
imageDTO = await getImageDTO(cachedImageName); imageDTO = await getImageDTO(cachedImageName);
@ -547,7 +539,7 @@ export class CanvasManager {
} }
imageDTO = await uploadImage(blob, 'composite-raster-layer.png', 'general', true); 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; return imageDTO;
}; };
@ -555,7 +547,7 @@ export class CanvasManager {
let imageDTO: ImageDTO | null = null; let imageDTO: ImageDTO | null = null;
const hash = this.getCompositeInpaintMaskHash({ rect }); const hash = this.getCompositeInpaintMaskHash({ rect });
const cachedImageName = this.imageNameCache.get(hash); const cachedImageName = this.cache.imageNameCache.get(hash);
if (cachedImageName) { if (cachedImageName) {
imageDTO = await getImageDTO(cachedImageName); imageDTO = await getImageDTO(cachedImageName);
@ -574,7 +566,7 @@ export class CanvasManager {
} }
imageDTO = await uploadImage(blob, 'composite-inpaint-mask.png', 'general', true); 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; return imageDTO;
}; };
@ -584,7 +576,7 @@ export class CanvasManager {
const compositeInpaintMaskHash = this.getCompositeInpaintMaskHash({ rect }); const compositeInpaintMaskHash = this.getCompositeInpaintMaskHash({ rect });
const compositeRasterLayerHash = this.getCompositeRasterLayerHash({ rect }); const compositeRasterLayerHash = this.getCompositeRasterLayerHash({ rect });
const hash = stableHash({ rect, compositeInpaintMaskHash, compositeRasterLayerHash }); const hash = stableHash({ rect, compositeInpaintMaskHash, compositeRasterLayerHash });
const cachedGenerationMode = this.generationModeCache.get(hash); const cachedGenerationMode = this.cache.generationModeCache.get(hash);
if (cachedGenerationMode) { if (cachedGenerationMode) {
this.log.trace({ rect, cachedGenerationMode }, 'Using cached generation mode'); this.log.trace({ rect, cachedGenerationMode }, 'Using cached generation mode');
@ -612,7 +604,7 @@ export class CanvasManager {
generationMode = 'inpaint'; generationMode = 'inpaint';
} }
this.generationModeCache.set(hash, generationMode); this.cache.generationModeCache.set(hash, generationMode);
return generationMode; return generationMode;
} }