@@ -75,35 +75,59 @@ export class CanvasStagingAreaModule extends CanvasModuleBase {
75
75
this . log . trace ( 'Rendering staging area' ) ;
76
76
const stagingArea = this . manager . stateApi . runSelector ( selectCanvasStagingAreaSlice ) ;
77
77
78
- const { x, y, width , height } = this . manager . stateApi . getBbox ( ) . rect ;
78
+ const { x, y } = this . manager . stateApi . getBbox ( ) . rect ;
79
79
const shouldShowStagedImage = this . $shouldShowStagedImage . get ( ) ;
80
80
81
81
this . selectedImage = stagingArea . stagedImages [ stagingArea . selectedStagedImageIndex ] ?? null ;
82
82
this . konva . group . position ( { x, y } ) ;
83
83
84
84
if ( this . selectedImage ) {
85
85
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
+ } ;
86
111
87
112
if ( ! this . image ) {
88
- const { image_name } = imageDTO ;
89
113
this . image = new CanvasObjectImage (
90
114
{
91
115
id : 'staging-area-image' ,
92
116
type : 'image' ,
93
- image : {
94
- image_name : image_name ,
95
- width,
96
- height,
97
- } ,
117
+ image,
98
118
} ,
99
119
this
100
120
) ;
121
+ await this . image . update ( this . image . state , true ) ;
101
122
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 ( ) ;
107
131
}
108
132
this . image . konva . group . visible ( shouldShowStagedImage ) ;
109
133
} else {
0 commit comments