slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.56k stars 604 forks source link

Provide an Interface for Multithreaded Image Loading #6397

Closed ArcticLampyrid closed 1 month ago

ArcticLampyrid commented 1 month ago

Loading some larger images is slow and may cause UI delays. To ensure a good user experience, multithreaded loading is necessary.

Currently the only way to load images in multiple threads currently is by loading the image as a PixelBuffer in another thread and then sending it to the main thread. This seems to imply that I need to make additional calls to an image library for decoding.

In fact, the built-in image decoding in Slint perfectly meets my needs; I just need an API like load_image_into_buffer.

tronical commented 1 month ago

Like this?:) https://docs.rs/slint/latest/slint/struct.Image.html#method.to_rgba8

ArcticLampyrid commented 1 month ago

Calling to_rgba8 requires the image to be loaded first, but I cannot call load_image_from_path on non-main thread.

ArcticLampyrid commented 1 month ago

Take the example from https://docs.rs/slint/latest/slint/struct.Image.html#sending-image-to-a-thread

std::thread::spawn(move || {
    let mut pixel_buffer = SharedPixelBuffer::<Rgba8Pixel>::new(640, 480);
    // ... fill the pixel_buffer with data as shown in the previous example ...
    slint::invoke_from_event_loop(move || {
        // this will run in the Slint's UI thread
        let image = Image::from_rgba8_premultiplied(pixel_buffer);
        // ... use the image, eg:
        // my_ui_handle.upgrade().unwrap().set_image(image);
    });
});

I'm looking forward that there is a thread-safe load_image_into_buffer, so that we can:

std::thread::spawn(move || {
    let pixel_buffer = load_image_into_buffer("/path/to/image");
    slint::invoke_from_event_loop(move || {
        // this will run in the Slint's UI thread
        let image = Image::from_rgba8_premultiplied(pixel_buffer);
        // ... use the image, eg:
        // my_ui_handle.upgrade().unwrap().set_image(image);
    });
});

Of course, the corresponding method should be available on the C++ side.

tronical commented 1 month ago

Calling to_rgba8 requires the image to be loaded first, but I cannot call load_image_from_path on non-main thread.

I wonder, why not?

The docs don’t do it because the Image isn’t send, but I think the extractable image buffer might be.

ArcticLampyrid commented 1 month ago

Oh, sorry, I mistakenly thought that function was only available on UI thread.

tronical commented 1 month ago

No worries :). I mean, it would be nice if image decoding was offloaded anyway in slint out of the box. But that might be tricky with the API right now. Let us know how it goes within your app and if you find something missing :)