Skip to content

Speed up copy for ImageBuffer#2766

Merged
197g merged 7 commits intomainfrom
efficient-copy
Feb 12, 2026
Merged

Speed up copy for ImageBuffer#2766
197g merged 7 commits intomainfrom
efficient-copy

Conversation

@197g
Copy link
Member

@197g 197g commented Feb 12, 2026

Benchmarks TBD but expecting ~60% performance or more. Motivation, context and approach from the first commit and follows pretty directly what was presented in the thoughts on #2553.

This has been a long standing issue. The lack of generalization in Rust
makes it generally hard to provide specialized implementations of
copy_from that can make full use of the layout information to improve
code generation. Since the argument is generic we stay with the default
implementation even for the very strict targets (and source) of
ImageBuffer.

We sidestep a large part of the problem by speeding up only the copy
from a well-described layout: View (a strided matrix). Then an
optional method on GenericImageView lets us query if the source is
equivalent to such a copy. We wont reap the benefits for user defined
trait impls but importantly the crate's own ImageBuffer and SubImage
can provide it The latter also has a generic impl for

SubImage<D> were <D as Deref>::Target: GenericImageView

Due to this we do not use a double-dispatch approach (adding a
copy_into_buffer) but this which composes purely at runtime.

Also note that DynamicImage can not provide it but the goal is to
replace this, too.

Closes: #2417, possibly #2553 (@fintelia addresses the immediate concern but we expanded the scope for reasons of extensibility concerns; but sealing the trait is already represented in another issue; your call)

197g added 6 commits February 12, 2026 22:45
This has been a long standing issue. The lack of generalization in Rust
makes it generally hard to provide specialized implementations of
`copy_from` that can make full use of the layout information to improve
code generation. Since the argument is generic we stay with the default
implementation even for the very strict targets (and source) of
`ImageBuffer`.

We sidestep a large part of the problem by speeding up only the copy
from a well-described layout: `View` (a strided matrix). Then an
optional method on `GenericImageView` lets us query if the source is
equivalent to such a copy. We wont reap the benefits for user defined
trait impls but importantly the crate's own `ImageBuffer` and `SubImage`
can provide it The latter also has a generic impl for

	SubImage<D> were <D as Deref>::Target: GenericImageView

Due to this we do not use a double-dispatch approach (adding a
`copy_into_buffer`) but this which composes purely at runtime.

Also note that DynamicImage can not provide it but the goal is to
replace this, too.
This also speeds up copies from them as well as copies from sub images
of sample views.
The pattern was caught in review, went ahead and generalized it to the
other occasion where a rectangular placement is built from an image.
@197g
Copy link
Member Author

197g commented Feb 12, 2026

Rebased so we can run complete benchmarks. Although, it does not seem necessary to justify this any further.

Details
copy_from               time:   [2.9246 ms 2.9460 ms 2.9688 ms]
                        change: [-25.357% -24.766% -24.149%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild

copy_at                 time:   [345.24 µs 346.54 µs 348.18 µs]
                        change: [-64.403% -63.765% -63.034%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 19 outliers among 100 measurements (19.00%)
  1 (1.00%) low mild
  9 (9.00%) high mild
  9 (9.00%) high severe

copy_view               time:   [552.29 µs 553.94 µs 556.02 µs]
                        change: [-78.457% -77.900% -77.345%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 14 outliers among 100 measurements (14.00%)
  1 (1.00%) low mild
  2 (2.00%) high mild
  11 (11.00%) high severe

copy_fill               time:   [704.57 µs 705.18 µs 705.79 µs]
                        change: [-78.583% -78.402% -78.128%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  2 (2.00%) high mild
  4 (4.00%) high severe

copy_strides            time:   [875.41 µs 876.36 µs 877.22 µs]
                        change: [-74.813% -74.428% -73.418%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 4 outliers among 100 measurements (4.00%)
  1 (1.00%) low mild
  2 (2.00%) high mild
  1 (1.00%) high severe

Since conversion is fallible, using `to_*` is more appropriate.
@197g 197g merged commit c4c8525 into main Feb 12, 2026
32 checks passed
@197g 197g deleted the efficient-copy branch February 12, 2026 23:42
@github-project-automation github-project-automation bot moved this from Backlog to Done in Release 0.25.* Feb 12, 2026
@197g 197g moved this from Done to Ready in Release 0.25.* Feb 13, 2026
@197g 197g mentioned this pull request Feb 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

Faster copy_from implementation

2 participants