mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
perf(ui): optimized object rendering
- Throttle opacity and compositing fill rendering to 100ms - Reduce compositing rect rendering to minimum
This commit is contained in:
@@ -39,6 +39,9 @@ export class CanvasEntityAdapterInpaintMask extends CanvasEntityAdapterBase<
|
||||
return;
|
||||
}
|
||||
|
||||
// If prevState is undefined, this is the first render. Some logic is only needed on the first render, or required
|
||||
// on first render.
|
||||
|
||||
if (!prevState || this.state.isEnabled !== prevState.isEnabled) {
|
||||
this.syncIsEnabled();
|
||||
}
|
||||
@@ -55,21 +58,16 @@ export class CanvasEntityAdapterInpaintMask extends CanvasEntityAdapterBase<
|
||||
this.syncOpacity();
|
||||
}
|
||||
if (!prevState || this.state.fill !== prevState.fill) {
|
||||
this.syncCompositingRectFill();
|
||||
// On first render, we must force the update
|
||||
this.renderer.updateCompositingRectFill(!prevState);
|
||||
}
|
||||
if (!prevState) {
|
||||
this.syncCompositingRectSize();
|
||||
// On first render, we must force the updates
|
||||
this.renderer.updateCompositingRectSize(true);
|
||||
this.renderer.updateCompositingRectPosition(true);
|
||||
}
|
||||
};
|
||||
|
||||
syncCompositingRectSize = () => {
|
||||
this.renderer.updateCompositingRectSize();
|
||||
};
|
||||
|
||||
syncCompositingRectFill = () => {
|
||||
this.renderer.updateCompositingRectFill();
|
||||
};
|
||||
|
||||
getHashableState = (): SerializableObject => {
|
||||
const keysToOmit: (keyof CanvasInpaintMaskState)[] = ['fill', 'name', 'opacity'];
|
||||
return omit(this.state, keysToOmit);
|
||||
|
||||
@@ -39,6 +39,9 @@ export class CanvasEntityAdapterRegionalGuidance extends CanvasEntityAdapterBase
|
||||
return;
|
||||
}
|
||||
|
||||
// If prevState is undefined, this is the first render. Some logic is only needed on the first render, or required
|
||||
// on first render.
|
||||
|
||||
if (!prevState || this.state.isEnabled !== prevState.isEnabled) {
|
||||
this.syncIsEnabled();
|
||||
}
|
||||
@@ -55,21 +58,16 @@ export class CanvasEntityAdapterRegionalGuidance extends CanvasEntityAdapterBase
|
||||
this.syncOpacity();
|
||||
}
|
||||
if (!prevState || this.state.fill !== prevState.fill) {
|
||||
this.syncCompositingRectFill();
|
||||
// On first render, we must force the update
|
||||
this.renderer.updateCompositingRectFill(!prevState);
|
||||
}
|
||||
if (!prevState) {
|
||||
this.syncCompositingRectSize();
|
||||
// On first render, we must force the updates
|
||||
this.renderer.updateCompositingRectSize(true);
|
||||
this.renderer.updateCompositingRectPosition(true);
|
||||
}
|
||||
};
|
||||
|
||||
syncCompositingRectSize = () => {
|
||||
this.renderer.updateCompositingRectSize();
|
||||
};
|
||||
|
||||
syncCompositingRectFill = () => {
|
||||
this.renderer.updateCompositingRectFill();
|
||||
};
|
||||
|
||||
getHashableState = (): SerializableObject => {
|
||||
const keysToOmit: (keyof CanvasRegionalGuidanceState)[] = ['fill', 'name', 'opacity'];
|
||||
return omit(this.state, keysToOmit);
|
||||
|
||||
@@ -25,6 +25,7 @@ import type { Rect } from 'features/controlLayers/store/types';
|
||||
import { imageDTOToImageObject } from 'features/controlLayers/store/util';
|
||||
import Konva from 'konva';
|
||||
import type { GroupConfig } from 'konva/lib/Group';
|
||||
import { throttle } from 'lodash-es';
|
||||
import type { Logger } from 'roarr';
|
||||
import { getImageDTOSafe, uploadImage } from 'services/api/endpoints/images';
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
@@ -131,13 +132,22 @@ export class CanvasEntityObjectRenderer extends CanvasModuleBase {
|
||||
// The compositing rect must cover the whole stage at all times. When the stage is scaled, moved or resized, we
|
||||
// need to update the compositing rect to match the stage.
|
||||
this.subscriptions.add(
|
||||
this.manager.stage.$stageAttrs.listen(() => {
|
||||
this.manager.stage.$stageAttrs.listen((stageAttrs, oldStageAttrs) => {
|
||||
if (!this.konva.compositing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.konva.compositing &&
|
||||
(this.parent.type === 'inpaint_mask_adapter' || this.parent.type === 'regional_guidance_adapter')
|
||||
stageAttrs.width !== oldStageAttrs.width ||
|
||||
stageAttrs.height !== oldStageAttrs.height ||
|
||||
stageAttrs.scale !== oldStageAttrs.scale
|
||||
) {
|
||||
this.updateCompositingRectSize();
|
||||
}
|
||||
|
||||
if (stageAttrs.x !== oldStageAttrs.x || stageAttrs.y !== oldStageAttrs.y) {
|
||||
this.updateCompositingRectPosition();
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -197,7 +207,11 @@ export class CanvasEntityObjectRenderer extends CanvasModuleBase {
|
||||
}
|
||||
};
|
||||
|
||||
updateCompositingRectFill = () => {
|
||||
updateCompositingRectFill = throttle((force?: boolean) => {
|
||||
if (!force && !this.hasObjects()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.log.trace('Updating compositing rect fill');
|
||||
|
||||
assert(this.konva.compositing, 'Missing compositing rect');
|
||||
@@ -216,9 +230,13 @@ export class CanvasEntityObjectRenderer extends CanvasModuleBase {
|
||||
});
|
||||
setFillPatternImage(this.konva.compositing.rect, fill.style, fill.color);
|
||||
}
|
||||
};
|
||||
}, 100);
|
||||
|
||||
updateCompositingRectSize = (force?: boolean) => {
|
||||
if (!force && !this.hasObjects()) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateCompositingRectSize = () => {
|
||||
this.log.trace('Updating compositing rect size');
|
||||
|
||||
assert(this.konva.compositing, 'Missing compositing rect');
|
||||
@@ -232,7 +250,21 @@ export class CanvasEntityObjectRenderer extends CanvasModuleBase {
|
||||
});
|
||||
};
|
||||
|
||||
updateOpacity = () => {
|
||||
updateCompositingRectPosition = (force?: boolean) => {
|
||||
if (!force && !this.hasObjects()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.log.trace('Updating compositing rect position');
|
||||
|
||||
assert(this.konva.compositing, 'Missing compositing rect');
|
||||
|
||||
this.konva.compositing.rect.setAttrs({
|
||||
...this.manager.stage.getScaledStageRect(),
|
||||
});
|
||||
};
|
||||
|
||||
updateOpacity = throttle(() => {
|
||||
this.log.trace('Updating opacity');
|
||||
|
||||
const opacity = this.parent.state.opacity;
|
||||
@@ -243,7 +275,7 @@ export class CanvasEntityObjectRenderer extends CanvasModuleBase {
|
||||
this.konva.objectGroup.opacity(opacity);
|
||||
}
|
||||
this.parent.bufferRenderer.konva.group.opacity(opacity);
|
||||
};
|
||||
}, 100);
|
||||
|
||||
/**
|
||||
* Renders the given object. If the object renderer does not exist, it will be created and its Konva group added to the
|
||||
|
||||
Reference in New Issue
Block a user