Skip to content

Commit

Permalink
[skwasm] use temporary RawPaint objects (attempt flutter#2) (flutter#…
Browse files Browse the repository at this point in the history
…55035)

Relands flutter#54917. The change is the same as before, except now the native resources for `SkwasmColorFilter` and `SkwasmImageFilter` classes are no longer GC'd. Instead, we use manually managed native handles (vended and scoped by `withRawColorFilter` and `withRawImageFilter`). The bug in the previous PR was that filter objects were disposed with the paint while the framework continued holding onto them. When GC kicked the finalization registry, it attempted to double-free the filters.
  • Loading branch information
yjbanov authored and jesswrd committed Sep 11, 2024
1 parent e83926b commit 6331379
Show file tree
Hide file tree
Showing 6 changed files with 379 additions and 350 deletions.
160 changes: 100 additions & 60 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,33 @@ class SkwasmCanvas implements SceneCanvas {

@override
void saveLayer(ui.Rect? bounds, ui.Paint paint) {
paint as SkwasmPaint;
final paintHandle = (paint as SkwasmPaint).toRawPaint();
if (bounds != null) {
withStackScope((StackScope s) {
canvasSaveLayer(_handle, s.convertRectToNative(bounds), paint.handle, nullptr);
canvasSaveLayer(_handle, s.convertRectToNative(bounds), paintHandle, nullptr);
});
} else {
canvasSaveLayer(_handle, nullptr, paint.handle, nullptr);
canvasSaveLayer(_handle, nullptr, paintHandle, nullptr);
}
paintDispose(paintHandle);
}

@override
void saveLayerWithFilter(ui.Rect? bounds, ui.Paint paint, ui.ImageFilter imageFilter) {
final SkwasmImageFilter nativeFilter = SkwasmImageFilter.fromUiFilter(imageFilter);
paint as SkwasmPaint;
final paintHandle = (paint as SkwasmPaint).toRawPaint();
if (bounds != null) {
withStackScope((StackScope s) {
canvasSaveLayer(_handle, s.convertRectToNative(bounds), paint.handle, nativeFilter.handle);
nativeFilter.withRawImageFilter((nativeFilterHandle) {
canvasSaveLayer(_handle, s.convertRectToNative(bounds), paintHandle, nativeFilterHandle);
});
});
} else {
canvasSaveLayer(_handle, nullptr, paint.handle, nativeFilter.handle);
nativeFilter.withRawImageFilter((nativeFilterHandle) {
canvasSaveLayer(_handle, nullptr, paintHandle, nativeFilterHandle);
});
}
paintDispose(paintHandle);
}

@override
Expand Down Expand Up @@ -111,136 +117,158 @@ class SkwasmCanvas implements SceneCanvas {

@override
void drawLine(ui.Offset p1, ui.Offset p2, ui.Paint paint) {
paint as SkwasmPaint;
canvasDrawLine(_handle, p1.dx, p1.dy, p2.dx, p2.dy, paint.handle);
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawLine(_handle, p1.dx, p1.dy, p2.dx, p2.dy, paintHandle);
paintDispose(paintHandle);
}

@override
void drawPaint(ui.Paint paint) {
paint as SkwasmPaint;
canvasDrawPaint(_handle, paint.handle);
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawPaint(_handle, paintHandle);
paintDispose(paintHandle);
}

@override
void drawRect(ui.Rect rect, ui.Paint paint) {
paint as SkwasmPaint;
final paintHandle = (paint as SkwasmPaint).toRawPaint();
withStackScope((StackScope s) {
canvasDrawRect(
_handle,
s.convertRectToNative(rect),
paint.handle
paintHandle
);
});
paintDispose(paintHandle);
}

@override
void drawRRect(ui.RRect rrect, ui.Paint paint) {
paint as SkwasmPaint;
final paintHandle = (paint as SkwasmPaint).toRawPaint();
withStackScope((StackScope s) {
canvasDrawRRect(
_handle,
s.convertRRectToNative(rrect),
paint.handle
paintHandle
);
});
paintDispose(paintHandle);
}

@override
void drawDRRect(ui.RRect outer, ui.RRect inner, ui.Paint paint) {
paint as SkwasmPaint;
final paintHandle = (paint as SkwasmPaint).toRawPaint();
withStackScope((StackScope s) {
canvasDrawDRRect(
_handle,
s.convertRRectToNative(outer),
s.convertRRectToNative(inner),
paint.handle
paintHandle
);
});
paintDispose(paintHandle);
}

@override
void drawOval(ui.Rect rect, ui.Paint paint) {
paint as SkwasmPaint;
final paintHandle = (paint as SkwasmPaint).toRawPaint();
withStackScope((StackScope s) {
canvasDrawOval(_handle, s.convertRectToNative(rect), paint.handle);
canvasDrawOval(_handle, s.convertRectToNative(rect), paintHandle);
});
paintDispose(paintHandle);
}

@override
void drawCircle(ui.Offset center, double radius, ui.Paint paint) {
paint as SkwasmPaint;
canvasDrawCircle(_handle, center.dx, center.dy, radius, paint.handle);
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawCircle(_handle, center.dx, center.dy, radius, paintHandle);
paintDispose(paintHandle);
}

@override
void drawArc(ui.Rect rect, double startAngle, double sweepAngle,
bool useCenter, ui.Paint paint) {
paint as SkwasmPaint;
final paintHandle = (paint as SkwasmPaint).toRawPaint();
withStackScope((StackScope s) {
canvasDrawArc(
_handle,
s.convertRectToNative(rect),
ui.toDegrees(startAngle),
ui.toDegrees(sweepAngle),
useCenter,
paint.handle
paintHandle,
);
});
paintDispose(paintHandle);
}

@override
void drawPath(ui.Path path, ui.Paint paint) {
paint as SkwasmPaint;
path as SkwasmPath;
canvasDrawPath(_handle, path.handle, paint.handle);
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawPath(_handle, path.handle, paintHandle);
paintDispose(paintHandle);
}

@override
void drawImage(ui.Image image, ui.Offset offset, ui.Paint paint) =>
void drawImage(ui.Image image, ui.Offset offset, ui.Paint paint) {
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawImage(
_handle,
(image as SkwasmImage).handle,
offset.dx,
offset.dy,
(paint as SkwasmPaint).handle,
paintHandle,
paint.filterQuality.index,
);
paintDispose(paintHandle);
}

@override
void drawImageRect(
ui.Image image,
ui.Rect src,
ui.Rect dst,
ui.Paint paint) => withStackScope((StackScope scope) {
final Pointer<Float> sourceRect = scope.convertRectToNative(src);
final Pointer<Float> destRect = scope.convertRectToNative(dst);
canvasDrawImageRect(
_handle,
(image as SkwasmImage).handle,
sourceRect,
destRect,
(paint as SkwasmPaint).handle,
paint.filterQuality.index,
);
});
ui.Paint paint,
) {
withStackScope((StackScope scope) {
final Pointer<Float> sourceRect = scope.convertRectToNative(src);
final Pointer<Float> destRect = scope.convertRectToNative(dst);
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawImageRect(
_handle,
(image as SkwasmImage).handle,
sourceRect,
destRect,
paintHandle,
paint.filterQuality.index,
);
paintDispose(paintHandle);
});
}

@override
void drawImageNine(
ui.Image image,
ui.Rect center,
ui.Rect dst,
ui.Paint paint) => withStackScope((StackScope scope) {
final Pointer<Int32> centerRect = scope.convertIRectToNative(center);
final Pointer<Float> destRect = scope.convertRectToNative(dst);
canvasDrawImageNine(
_handle,
(image as SkwasmImage).handle,
centerRect,
destRect,
(paint as SkwasmPaint).handle,
paint.filterQuality.index,
);
});
ui.Paint paint,
) {
withStackScope((StackScope scope) {
final Pointer<Int32> centerRect = scope.convertIRectToNative(center);
final Pointer<Float> destRect = scope.convertRectToNative(dst);
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawImageNine(
_handle,
(image as SkwasmImage).handle,
centerRect,
destRect,
paintHandle,
paint.filterQuality.index,
);
paintDispose(paintHandle);
});
}

@override
void drawPicture(ui.Picture picture) {
Expand All @@ -264,13 +292,15 @@ class SkwasmCanvas implements SceneCanvas {
ui.Paint paint
) => withStackScope((StackScope scope) {
final RawPointArray rawPoints = scope.convertPointArrayToNative(points);
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawPoints(
_handle,
pointMode.index,
rawPoints,
points.length,
(paint as SkwasmPaint).handle,
paintHandle,
);
paintDispose(paintHandle);
});

@override
Expand All @@ -280,26 +310,32 @@ class SkwasmCanvas implements SceneCanvas {
ui.Paint paint
) => withStackScope((StackScope scope) {
final RawPointArray rawPoints = scope.convertDoublesToNative(points);
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawPoints(
_handle,
pointMode.index,
rawPoints,
points.length ~/ 2,
(paint as SkwasmPaint).handle,
paintHandle,
);
paintDispose(paintHandle);
});

@override
void drawVertices(
ui.Vertices vertices,
ui.BlendMode blendMode,
ui.Paint paint,
) => canvasDrawVertices(
_handle,
(vertices as SkwasmVertices).handle,
blendMode.index,
(paint as SkwasmPaint).handle,
);
) {
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawVertices(
_handle,
(vertices as SkwasmVertices).handle,
blendMode.index,
paintHandle,
);
paintDispose(paintHandle);
}

@override
void drawAtlas(
Expand All @@ -319,6 +355,7 @@ class SkwasmCanvas implements SceneCanvas {
final RawRect rawCullRect = cullRect != null
? scope.convertRectToNative(cullRect)
: nullptr;
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawAtlas(
_handle,
(atlas as SkwasmImage).handle,
Expand All @@ -328,8 +365,9 @@ class SkwasmCanvas implements SceneCanvas {
transforms.length,
(blendMode ?? ui.BlendMode.src).index,
rawCullRect,
(paint as SkwasmPaint).handle,
paintHandle,
);
paintDispose(paintHandle);
});

@override
Expand All @@ -350,6 +388,7 @@ class SkwasmCanvas implements SceneCanvas {
final RawRect rawCullRect = cullRect != null
? scope.convertRectToNative(cullRect)
: nullptr;
final paintHandle = (paint as SkwasmPaint).toRawPaint();
canvasDrawAtlas(
_handle,
(atlas as SkwasmImage).handle,
Expand All @@ -359,8 +398,9 @@ class SkwasmCanvas implements SceneCanvas {
rstTransforms.length ~/ 4,
(blendMode ?? ui.BlendMode.src).index,
rawCullRect,
(paint as SkwasmPaint).handle,
paintHandle,
);
paintDispose(paintHandle);
});

@override
Expand Down
Loading

0 comments on commit 6331379

Please sign in to comment.