Skip to content
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

Put repaint callback and tex manager behind separate mutexes #1389

Closed
wants to merge 3 commits into from

Conversation

emilk
Copy link
Owner

@emilk emilk commented Mar 20, 2022

Closes #1379

Please take a look @DusterTheFirst

This fattens up Context so that the repaint callback and texture manager can be used from any thread, even when you are not compiling with the multi_threaded feature flag:

pub struct Context {
    ctx: Arc<RwLock<ContextImpl>>,
    repaint_info: Arc<RepaintInfo>,
    tex_manager: WrappedTextureManager,
}

This is one solution, but I'm not sure it is the best one.

The solution in this PR has the added advantage of mitigating #1380


Performance: the e2e tests shows very little change, but some specific tests (Painter::rect and label format!) shows 10% slowdowns.


I think the simpler solution is to remove the single_threaded/multi_threaded features and to always use proper mutexes, as proposed in:

emilk added a commit that referenced this pull request Mar 20, 2022
Always use parking_lot for mutexes, i.e. always be multi-threaded.

Closes #1379

An alternative to #1389
emilk added a commit that referenced this pull request Mar 21, 2022
Always use parking_lot for mutexes, i.e. always be multi-threaded.

Closes #1379

An alternative to #1389
@emilk emilk force-pushed the fix-request-repaint-thread-safety branch from 414079b to 6a3e7d1 Compare March 21, 2022 15:40
@emilk emilk changed the title Fix request repaint thread safety Put repaint callback and tex manager behind separate mutexes Mar 21, 2022
@DusterTheFirst
Copy link
Contributor

DusterTheFirst commented Mar 21, 2022

Do you have an idea of how these changes caused such an observable slow down in those specific test cases? Looking through the changes, I cannot see a clear cause for the slowdown.

Note: I was unable to reproduce the slowdowns using cargo bench on my computer (Windows 10 Enterprise, i7-10750H, 16GB 2933Mhz)

emilk added a commit that referenced this pull request Mar 22, 2022
https://github.com/asny/three-d recently merged a PR adding
`glow` support: asny/three-d#210
This means it is a prime candidate for embedding 3D painting inside
an eframe app.

There are currently a few kinks that need to be figured out:

### Black screen
When reusing the same three_d context over time (as one should),
we only get one frame of egui together with three_d, and then after that
a black screen with just the three_d painting on top.

I need to fix that before merging this PR.

### `Shape: Send + Sync`
`Shape` is `Send + Sync` and `three_d::Context` is not. This means
we cannot store a three_d context and send it to the `Shape::Callback`.

So we either need to recreate the three_d context each frame (obviously
a bad idea), or access it through a `thread_local` hack.
This PR adds both as examples, with a checkbox to switch.

We could consider making `Shape: !Send + !Sync`, but that would mean
`egui::Context` could not be `Send+Sync` either (because the egui
context stores shapes). This could actually be fine. `egui::Context`
should only be used from a background thread for calling request_repaint
and allocating textures. These could be made separate parts of the
egui Context, so that one would do:

``` rust

let repaint_signal = egui_ctx.repaint_signal();
let tex_mngr = egui_ctx.tex_mngr();
std::thread::spawn(move || {
    // We can use repaint_signal and tex_mngr here,
    // but NOT `egui_ctx`.
}):

Related:
* #1379
* #1380
* #1389
emilk added a commit that referenced this pull request Mar 22, 2022
https://github.com/asny/three-d recently merged a PR adding
`glow` support: asny/three-d#210
This means it is a prime candidate for embedding 3D painting inside
an eframe app.

There are currently a few kinks that need to be figured out:

When reusing the same three_d context over time (as one should),
we only get one frame of egui together with three_d, and then after that
a black screen with just the three_d painting on top.

I need to fix that before merging this PR.

`Shape` is `Send + Sync` and `three_d::Context` is not. This means
we cannot store a three_d context and send it to the `Shape::Callback`.

So we either need to recreate the three_d context each frame (obviously
a bad idea), or access it through a `thread_local` hack.
This PR adds both as examples, with a checkbox to switch.

We could consider making `Shape: !Send + !Sync`, but that would mean
`egui::Context` could not be `Send+Sync` either (because the egui
context stores shapes). This could actually be fine. `egui::Context`
should only be used from a background thread for calling request_repaint
and allocating textures. These could be made separate parts of the
egui Context, so that one would do:

``` rust

let repaint_signal = egui_ctx.repaint_signal();
let tex_mngr = egui_ctx.tex_mngr();
std::thread::spawn(move || {
    // We can use repaint_signal and tex_mngr here,
    // but NOT `egui_ctx`.
}):

Related:
* #1379
* #1380
* #1389
@emilk emilk closed this Jul 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Changes to the repaint signal causes problems with multi-threaded code
2 participants