Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b9a7234

Browse files
[web] retain GL/Gr context on window resize (#38576)
* [web] dont dispose of context on window resize * ++ * ++ * ++ * ++ * ++ * ++ * always re-create surface * ++ * ++
1 parent ae9e181 commit b9a7234

File tree

2 files changed

+42
-35
lines changed

2 files changed

+42
-35
lines changed

lib/web_ui/lib/src/engine/canvaskit/surface.dart

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ import 'util.dart';
1919

2020
// Only supported in profile/release mode. Allows Flutter to use MSAA but
2121
// removes the ability for disabling AA on Paint objects.
22-
const bool _kUsingMSAA =
23-
bool.fromEnvironment('flutter.canvaskit.msaa');
22+
const bool _kUsingMSAA = bool.fromEnvironment('flutter.canvaskit.msaa');
2423

2524
typedef SubmitCallback = bool Function(SurfaceFrame, CkCanvas);
2625

@@ -146,53 +145,60 @@ class Surface {
146145
throw CanvasKitError('Cannot create surfaces of empty size.');
147146
}
148147

149-
// Check if the window is the same size as before, and if so, don't allocate
150-
// a new canvas as the previous canvas is big enough to fit everything.
151-
final ui.Size? previousSurfaceSize = _currentSurfaceSize;
152-
if (!_forceNewContext &&
153-
previousSurfaceSize != null &&
154-
size.width == previousSurfaceSize.width &&
155-
size.height == previousSurfaceSize.height) {
156-
// The existing surface is still reusable.
157-
if (window.devicePixelRatio != _currentDevicePixelRatio) {
158-
_updateLogicalHtmlCanvasSize();
159-
_translateCanvas();
148+
if (!_forceNewContext) {
149+
// Check if the window is the same size as before, and if so, don't allocate
150+
// a new canvas as the previous canvas is big enough to fit everything.
151+
final ui.Size? previousSurfaceSize = _currentSurfaceSize;
152+
if (previousSurfaceSize != null &&
153+
size.width == previousSurfaceSize.width &&
154+
size.height == previousSurfaceSize.height) {
155+
// The existing surface is still reusable.
156+
if (window.devicePixelRatio != _currentDevicePixelRatio) {
157+
_updateLogicalHtmlCanvasSize();
158+
_translateCanvas();
159+
}
160+
return _surface!;
160161
}
161-
return _surface!;
162-
}
163162

164-
// If the current canvas size is smaller than the requested size then create
165-
// a new, larger, canvas. Then update the GR context so we can create a new
166-
// SkSurface.
167-
final ui.Size? previousCanvasSize = _currentCanvasPhysicalSize;
168-
if (_forceNewContext ||
169-
previousCanvasSize == null ||
170-
size.width > previousCanvasSize.width ||
171-
size.height > previousCanvasSize.height) {
163+
final ui.Size? previousCanvasSize = _currentCanvasPhysicalSize;
172164
// Initialize a new, larger, canvas. If the size is growing, then make the
173165
// new canvas larger than required to avoid many canvas creations.
174-
final ui.Size newSize = previousCanvasSize == null ? size : size * 1.4;
166+
if (previousCanvasSize != null &&
167+
(size.width > previousCanvasSize.width ||
168+
size.height > previousCanvasSize.height)) {
169+
final ui.Size newSize = size * 1.4;
170+
_surface?.dispose();
171+
_surface = null;
172+
htmlCanvas!.width = newSize.width;
173+
htmlCanvas!.height = newSize.height;
174+
_currentCanvasPhysicalSize = newSize;
175+
_pixelWidth = newSize.width.ceil();
176+
_pixelHeight = newSize.height.ceil();
177+
_updateLogicalHtmlCanvasSize();
178+
}
179+
}
175180

176-
// If we have a surface, send a dummy command to its canvas to make its context
177-
// current or else disposing the context could fail below.
178-
_surface?.getCanvas().clear(const ui.Color(0x00000000));
181+
// Either a new context is being forced or we've never had one.
182+
if (_forceNewContext || _currentCanvasPhysicalSize == null) {
179183
_surface?.dispose();
180184
_surface = null;
181185
_addedToScene = false;
182186
_grContext?.releaseResourcesAndAbandonContext();
183187
_grContext?.delete();
184188
_grContext = null;
185189

186-
_createNewCanvas(newSize);
187-
_currentCanvasPhysicalSize = newSize;
190+
_createNewCanvas(size);
191+
_currentCanvasPhysicalSize = size;
188192
} else if (window.devicePixelRatio != _currentDevicePixelRatio) {
189193
_updateLogicalHtmlCanvasSize();
190194
}
191195

192196
_currentDevicePixelRatio = window.devicePixelRatio;
193197
_currentSurfaceSize = size;
194198
_translateCanvas();
195-
return _surface = _createNewSurface(size);
199+
_surface?.dispose();
200+
_surface = _createNewSurface(size);
201+
return _surface!;
196202
}
197203

198204
/// Sets the CSS size of the canvas so that canvas pixels are 1:1 with device

lib/web_ui/test/canvaskit/surface_test.dart

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,25 @@ void testMain() {
3737
expect(originalSurface.width(), 9);
3838
expect(originalSurface.height(), 19);
3939

40-
// Shrinking reuses the existing canvas but translates it so Skia renders into the visible area.
40+
// Shrinking reuses the existing canvas but translates it so
41+
// Skia renders into the visible area.
4142
final CkSurface shrunkSurface =
4243
surface.acquireFrame(const ui.Size(5, 15)).skiaSurface;
4344
final DomCanvasElement shrunk = surface.htmlCanvas!;
4445
expect(shrunk, same(original));
4546
expect(shrunk.style.width, '9px');
4647
expect(shrunk.style.height, '19px');
4748
expect(shrunk.style.transform, _isTranslate(0, -4));
48-
expect(shrunkSurface, isNot(same(original)));
49+
expect(shrunkSurface, isNot(same(originalSurface)));
4950
expect(shrunkSurface.width(), 5);
5051
expect(shrunkSurface.height(), 15);
5152

52-
// The first increase will allocate a new canvas, but will overallocate
53+
// The first increase will allocate a new surface, but will overallocate
5354
// by 40% to accommodate future increases.
5455
final CkSurface firstIncreaseSurface =
5556
surface.acquireFrame(const ui.Size(10, 20)).skiaSurface;
5657
final DomCanvasElement firstIncrease = surface.htmlCanvas!;
57-
expect(firstIncrease, isNot(same(original)));
58+
expect(firstIncrease, same(original));
5859
expect(firstIncreaseSurface, isNot(same(shrunkSurface)));
5960

6061
// Expect overallocated dimensions
@@ -79,7 +80,7 @@ void testMain() {
7980
// Increases beyond the 40% limit will cause a new allocation.
8081
final CkSurface hugeSurface = surface.acquireFrame(const ui.Size(20, 40)).skiaSurface;
8182
final DomCanvasElement huge = surface.htmlCanvas!;
82-
expect(huge, isNot(same(secondIncrease)));
83+
expect(huge, same(secondIncrease));
8384
expect(hugeSurface, isNot(same(secondIncreaseSurface)));
8485

8586
// Also over-allocated

0 commit comments

Comments
 (0)