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

[web] use a render target instead of a new surface for Picture.toImage #38573

Merged
merged 16 commits into from
Jan 25, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ extension CanvasKitExtension on CanvasKit {
int height,
ColorSpace colorSpace,
);
external SkSurface? MakeRenderTarget(
SkGrContext grContext,
int width,
int height,
);
external SkSurface MakeSWCanvasSurface(DomCanvasElement canvas);

/// Creates an image from decoded pixels represented as a list of bytes.
Expand Down
21 changes: 3 additions & 18 deletions lib/web_ui/lib/src/engine/canvaskit/picture.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:typed_data';

import 'package:ui/ui.dart' as ui;

import '../profiler.dart';
Expand Down Expand Up @@ -102,26 +100,13 @@ class CkPicture extends ManagedSkiaObject<SkPicture> implements ui.Picture {
@override
ui.Image toImageSync(int width, int height) {
assert(debugCheckNotDisposed('Cannot convert picture to image.'));
final Surface surface = SurfaceFactory.instance.pictureToImageSurface;
final CkSurface ckSurface =
surface.createOrUpdateSurface(ui.Size(width.toDouble(), height.toDouble()));
final CkSurface ckSurface = SurfaceFactory.instance.baseSurface
.createRenderTargetSurface(ui.Size(width.toDouble(), height.toDouble()));
final CkCanvas ckCanvas = ckSurface.getCanvas();
ckCanvas.clear(const ui.Color(0x00000000));
ckCanvas.drawPicture(this);
final SkImage skImage = ckSurface.surface.makeImageSnapshot();
final SkImageInfo imageInfo = SkImageInfo(
alphaType: canvasKit.AlphaType.Premul,
colorType: canvasKit.ColorType.RGBA_8888,
colorSpace: SkColorSpaceSRGB,
width: width,
height: height,
);
final Uint8List pixels = skImage.readPixels(0, 0, imageInfo);
final SkImage? rasterImage = canvasKit.MakeImage(imageInfo, pixels, 4 * width);
if (rasterImage == null) {
throw StateError('Unable to convert image pixels into SkImage.');
}
return CkImage(rasterImage);
return CkImage(skImage);
}

@override
Expand Down
25 changes: 25 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/surface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,31 @@ class Surface {
ui.Size? _currentSurfaceSize;
double _currentDevicePixelRatio = -1;

CkSurface createRenderTargetSurface(ui.Size size) {
// If the GrContext hasn't been setup yet then we need to force initialization
// of the canvas and initial surface.
if (_surface == null) {
assert(_grContext == null);
assert(_glContext == null);
_createNewCanvas(window.physicalSize);
_currentCanvasPhysicalSize = window.physicalSize;
_currentDevicePixelRatio = window.devicePixelRatio;
_currentSurfaceSize = window.physicalSize;
_translateCanvas();
_surface = _createNewSurface(window.physicalSize);
}
final SkSurface? skSurface = canvasKit.MakeRenderTarget(
_grContext!,
size.width.ceil(),
size.height.ceil(),
);
if (skSurface == null) {
return _makeSoftwareCanvasSurface(
htmlCanvas!, 'Failed to initialize WebGL surface');
}
return CkSurface(skSurface, _glContext);
}

/// Creates a <canvas> and SkSurface for the given [size].
CkSurface createOrUpdateSurface(ui.Size size) {
if (size.isEmpty) {
Expand Down
4 changes: 0 additions & 4 deletions lib/web_ui/lib/src/engine/canvaskit/surface_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ class SurfaceFactory {
/// all painting commands.
final Surface baseSurface = Surface();

/// A surface used specifically for `Picture.toImage` calls, which can be
/// reused in order to avoid creating too many WebGL contexts.
late final Surface pictureToImageSurface = Surface();

/// The maximum number of surfaces which can be live at once.
final int maximumSurfaces;

Expand Down
4 changes: 0 additions & 4 deletions lib/web_ui/test/canvaskit/surface_factory_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ void testMain() {
expect(SurfaceFactory(2).maximumSurfaces, 2);
});

test('has a Surface dedicated to Picture.toImage', () {
expect(SurfaceFactory(1).pictureToImageSurface, isNotNull);
});

test('getSurface', () {
final SurfaceFactory factory = SurfaceFactory(3);
expect(factory.baseSurface, isNotNull);
Expand Down