Skip to content

Commit 5f1a30e

Browse files
fix(ui): flicker when transitioning from an output image to next generation's progress image
1 parent d09e600 commit 5f1a30e

File tree

1 file changed

+36
-12
lines changed

1 file changed

+36
-12
lines changed

invokeai/frontend/web/src/features/controlLayers/konva/CanvasStagingAreaModule.ts

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,35 +75,59 @@ export class CanvasStagingAreaModule extends CanvasModuleBase {
7575
this.log.trace('Rendering staging area');
7676
const stagingArea = this.manager.stateApi.runSelector(selectCanvasStagingAreaSlice);
7777

78-
const { x, y, width, height } = this.manager.stateApi.getBbox().rect;
78+
const { x, y } = this.manager.stateApi.getBbox().rect;
7979
const shouldShowStagedImage = this.$shouldShowStagedImage.get();
8080

8181
this.selectedImage = stagingArea.stagedImages[stagingArea.selectedStagedImageIndex] ?? null;
8282
this.konva.group.position({ x, y });
8383

8484
if (this.selectedImage) {
8585
const { imageDTO } = this.selectedImage;
86+
const image = imageDTOToImageWithDims(imageDTO);
87+
88+
/**
89+
* When the final output image of a generation is received, we should clear that generation's last progress image.
90+
*
91+
* It's possible that we have already rendered the progress image from the next generation before the output image
92+
* from the previous is fully loaded/rendered. This race condition results in a flicker:
93+
* - LAST GENERATION: Render the final progress image
94+
* - LAST GENERATION: Start loading the final output image...
95+
* - NEXT GENERATION: Render the first progress image
96+
* - LAST GENERATION: ...Finish loading the final output image & render it, clearing the progress image <-- Flicker!
97+
* - NEXT GENERATION: Render the next progress image
98+
*
99+
* We can detect the race condition by stashing the session ID of the last progress image when we begin loading
100+
* that session's output image. After we render it, if the progress image's session ID is the same as the one we
101+
* stashed, we know that we have not yet gotten that next generation's first progress image. We can clear the
102+
* progress image without causing a flicker.
103+
*/
104+
const lastProgressEventSessionId = this.manager.progressImage.$lastProgressEvent.get()?.session_id;
105+
const hideProgressIfSameSession = () => {
106+
const currentProgressEventSessionId = this.manager.progressImage.$lastProgressEvent.get()?.session_id;
107+
if (lastProgressEventSessionId === currentProgressEventSessionId) {
108+
this.manager.progressImage.$lastProgressEvent.set(null);
109+
}
110+
};
86111

87112
if (!this.image) {
88-
const { image_name } = imageDTO;
89113
this.image = new CanvasObjectImage(
90114
{
91115
id: 'staging-area-image',
92116
type: 'image',
93-
image: {
94-
image_name: image_name,
95-
width,
96-
height,
97-
},
117+
image,
98118
},
99119
this
100120
);
121+
await this.image.update(this.image.state, true);
101122
this.konva.group.add(this.image.konva.group);
102-
}
103-
104-
if (!this.image.isLoading && !this.image.isError) {
105-
await this.image.update({ ...this.image.state, image: imageDTOToImageWithDims(imageDTO) }, true);
106-
this.manager.progressImage.$lastProgressEvent.set(null);
123+
hideProgressIfSameSession();
124+
} else if (this.image.isLoading) {
125+
// noop - just wait for the image to load
126+
} else if (this.image.isError) {
127+
hideProgressIfSameSession();
128+
} else if (this.image.state.image.image_name !== image.image_name) {
129+
await this.image.update({ ...this.image.state, image }, true);
130+
hideProgressIfSameSession();
107131
}
108132
this.image.konva.group.visible(shouldShowStagedImage);
109133
} else {

0 commit comments

Comments
 (0)