Skip to content

perf: avoid memcpy while drawing canvas on canvas #984

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
22 changes: 3 additions & 19 deletions .github/workflows/CI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ jobs:
fail-fast: false
matrix:
node: ['20', '22']
runs-on: ubuntu-latest
runs-on: ubuntu-24.04-arm

steps:
- uses: actions/checkout@v4
Expand All @@ -473,16 +473,7 @@ jobs:
shell: bash

- name: Install dependencies
run: |
yarn config set supportedArchitectures.cpu "arm64"
yarn config set supportedArchitectures.libc "glibc"
yarn install --immutable --mode=skip-build
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64

- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
run: yarn install --immutable --mode=skip-build

- name: Setup and run tests
uses: addnab/docker-run-action@v3
Expand All @@ -506,7 +497,7 @@ jobs:
needs:
- build

runs-on: ubuntu-latest
runs-on: ubuntu-24.04-arm

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -536,13 +527,6 @@ jobs:
yarn config set supportedArchitectures.libc "musl"
yarn install --immutable --mode=skip-build

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64

- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

- name: Setup and run tests
uses: addnab/docker-run-action@v3
with:
Expand Down
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ fn main() {
.cpp_set_stdlib("stdc++")
.flag("-static")
.include("/usr/arm-linux-gnueabihf/include")
.include(format!("/usr/arm-linux-gnueabihf/include/c++/8"));
.include("/usr/arm-linux-gnueabihf/include/c++/8");
println!("cargo:rustc-link-lib=static=stdc++");
println!("cargo:rustc-link-search=/usr/lib/gcc-cross/arm-linux-gnueabihf/8");
}
Expand Down
25 changes: 15 additions & 10 deletions skia-c/skia_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,14 +293,10 @@ extern "C"

void skiac_surface_get_bitmap(skiac_surface *c_surface, skiac_bitmap_info *info)
{
auto image = SURFACE_CAST->makeImageSnapshot();
auto bitmap = new SkBitmap();
auto image_info = image->imageInfo();
bitmap->allocPixels(image_info);
image->readPixels(image_info, bitmap->getPixels(), bitmap->rowBytes(), 0, 0);
info->bitmap = reinterpret_cast<skiac_bitmap *>(bitmap);
info->width = (size_t)image_info.width();
info->height = (size_t)image_info.height();
info->is_canvas = true;
info->bitmap = reinterpret_cast<skiac_bitmap *>(c_surface);
info->width = (size_t)SURFACE_CAST->width();
info->height = (size_t)SURFACE_CAST->height();
}

// Canvas
Expand Down Expand Up @@ -354,6 +350,7 @@ extern "C"
void skiac_canvas_draw_image(
skiac_canvas *c_canvas,
skiac_bitmap *c_bitmap,
bool is_canvas,
float sx,
float sy,
float s_width,
Expand All @@ -368,11 +365,19 @@ extern "C"
{
const auto src_rect = SkRect::MakeXYWH(sx, sy, s_width, s_height);
const auto dst_rect = SkRect::MakeXYWH(dx, dy, d_width, d_height);
auto sk_image = SkImages::RasterFromBitmap(*BITMAP_CAST);
auto fq = enable_smoothing ? filter_quality : 0;
const auto sampling = SamplingOptionsFromFQ(fq);
auto paint = reinterpret_cast<const SkPaint *>(c_paint);
CANVAS_CAST->drawImageRect(sk_image, src_rect, dst_rect, sampling, paint, SkCanvas::kFast_SrcRectConstraint);
if (is_canvas) {
auto srcSurface = reinterpret_cast<SkSurface *>(c_bitmap);
CANVAS_CAST->save();
CANVAS_CAST->translate(dx, dy);
CANVAS_CAST->clipRect(SkRect::MakeWH(d_width, d_height));
srcSurface->draw(CANVAS_CAST, -sx, -sy, sampling, paint);
CANVAS_CAST->restore();
} else {
CANVAS_CAST->drawImageRect(SkImages::RasterFromBitmap(*BITMAP_CAST), src_rect, dst_rect, sampling, paint, SkCanvas::kFast_SrcRectConstraint);
}
}

void skiac_canvas_draw_path(skiac_canvas *c_canvas, skiac_path *c_path, skiac_paint *c_paint)
Expand Down
2 changes: 2 additions & 0 deletions skia-c/skia_c.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ struct skiac_bitmap_info
skiac_bitmap *bitmap;
int width;
int height;
bool is_canvas;
};

struct skiac_string
Expand Down Expand Up @@ -294,6 +295,7 @@ extern "C"
void skiac_canvas_draw_image(
skiac_canvas *c_canvas,
skiac_bitmap *c_bitmap,
bool is_canvas,
float sx,
float sy,
float s_width,
Expand Down
1 change: 0 additions & 1 deletion src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,6 @@ impl Context {
d_width: f32,
d_height: f32,
) -> Result<()> {
let bitmap = bitmap.0.bitmap;
let mut paint: Paint = self.fill_paint()?;
paint.set_alpha((self.state.global_alpha * 255.0).round() as u8);
Self::render_canvas(
Expand Down
18 changes: 14 additions & 4 deletions src/sk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ pub mod ffi {
pub bitmap: *mut skiac_bitmap,
pub width: i32,
pub height: i32,
pub is_canvas: bool,
}

#[repr(C)]
Expand Down Expand Up @@ -373,6 +374,7 @@ pub mod ffi {
pub fn skiac_canvas_draw_image(
canvas: *mut skiac_canvas,
bitmap: *mut skiac_bitmap,
is_image: bool,
sx: f32,
sy: f32,
s_width: f32,
Expand Down Expand Up @@ -1822,6 +1824,7 @@ impl Surface {
bitmap: ptr::null_mut(),
width: 0,
height: 0,
is_canvas: true,
};
unsafe { ffi::skiac_surface_get_bitmap(self.ptr, &mut bitmap_info) };
Bitmap(bitmap_info)
Expand Down Expand Up @@ -2068,7 +2071,7 @@ impl Canvas {

pub fn draw_image(
&mut self,
image: *mut ffi::skiac_bitmap,
image: &Bitmap,
sx: f32,
sy: f32,
s_width: f32,
Expand All @@ -2084,7 +2087,8 @@ impl Canvas {
unsafe {
ffi::skiac_canvas_draw_image(
self.0,
image,
image.0.bitmap,
image.0.is_canvas,
sx,
sy,
s_width,
Expand Down Expand Up @@ -3439,7 +3443,7 @@ impl Drop for ImageFilter {

#[repr(transparent)]
#[derive(Debug)]
pub(crate) struct Bitmap(pub(crate) ffi::skiac_bitmap_info);
pub struct Bitmap(pub(crate) ffi::skiac_bitmap_info);

unsafe impl Send for Bitmap {}
unsafe impl Sync for Bitmap {}
Expand All @@ -3450,6 +3454,7 @@ impl Bitmap {
bitmap: ptr::null_mut(),
width: 0,
height: 0,
is_canvas: false,
};
unsafe {
ffi::skiac_bitmap_make_from_buffer(ptr, size, &mut bitmap_info);
Expand All @@ -3467,6 +3472,7 @@ impl Bitmap {
bitmap: ptr::null_mut(),
width: 0,
height: 0,
is_canvas: false,
};
unsafe {
let is_valid = ffi::skiac_bitmap_make_from_svg(
Expand Down Expand Up @@ -3502,6 +3508,7 @@ impl Bitmap {
bitmap: ptr::null_mut(),
width: 0,
height: 0,
is_canvas: false,
};
unsafe {
ffi::skiac_bitmap_make_from_svg(
Expand Down Expand Up @@ -3545,14 +3552,17 @@ impl Bitmap {
bitmap,
width: row_bytes as i32,
height: (size / row_bytes / 4) as i32,
is_canvas: false,
})
}
}

impl Drop for Bitmap {
fn drop(&mut self) {
unsafe {
ffi::skiac_bitmap_destroy(self.0.bitmap);
if !self.0.is_canvas {
ffi::skiac_bitmap_destroy(self.0.bitmap);
}
}
}
}
Expand Down