-
Notifications
You must be signed in to change notification settings - Fork 48
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
Owned pixel buffer for no-copy presentation #65
Conversation
This is based on the API that will be used for no-copy presentation. But wraps it in `set_buffer`. This also fixes the wayland buffer code to set `self.width` and `self.height` on resize, and set the length of the shared memory file when the buffer is created.
Currently only for `wayland` and the `winit` example.
Benchmarking is always subtle and easy to mess up, but comparing the time It makes sense that this would be pretty efficient. In the |
Added code for Windows, using I guess it would be possible to write some portable automated tests |
I added the X11 implementation for this. While we're rewriting the API, do we want to make these functions return |
Yeah, the question is whether every method should return a For the public API, we should generally document what blocking, panicking, and errors are expected in each call. Including platform specific concerns if relevant. |
At the very least, Also, I added support to the web backend for this PR. |
So a lot of the questions here are tied to the design of the public API: Surface sizes
Thread-safety
Error handling
Documentation
|
My opinions, in no particular order:
We should return an error instead; the maximum size varies between backends, so this is a legitimate failure state rather than an unexpected issue.
I don't think this is a good idea;
Silently ignoring errors is a recipe for disaster, I disagree with this on principle.
Yes, we should use
Yes, to future-proof it.
|
If the size is simply passed along from winit we know it must already be in range for the backend. (Are there expected uses where it might pass something out of range?). But returning an error is easy enough if we're making that function return a
In the Wayland backend, That could be moved to
Well, specifically if the error is permanent loss of connection to the display server, it would be fine since we'd be guaranteed to get the exact same error when
It also lets use use
Hm. Hadn't thought of that option. I guess a default doesn't entirely make sense. Either that isn't what you wanted, and a panic would be clearer, or if you really want that you can just call Currently in the But if we add an option for |
We should probably have a test to ensure that the Send and Sync impls are correct. I believe the static_assertions crate can do that |
A simple macOS implementation for this API could just store a @jackpot51 I'm not sure how this would be handled in the Orbital implementation. Unlike the others it fetches the current size of the window and maps it, then iterates over |
Still probably not the most efficient implementation.
Oh, I guess the size of the window on orbital only changes when the client sends a call to change it. So that makes sense but clashes somewhat with the way the API here works. Probably the size should match, but we don't want to panic when a size that doesn't match the window size is passed. |
You can't really do that, since you'd need to specify a negative bound. However, you can do: /// ```compile_fail
/// use softbuffer::Context;
/// fn needs_send<T: Send>() {}
/// needs_send::<Context>();
/// ```
/// ```compile_fail
/// use softbuffer::Surface;
/// fn needs_send<T: Send>() {}
/// needs_send::<Surface>();
/// ```
extern "C" {}
While we're at it, |
assert_not_impl_all is in static_assertions and should work. |
Huh, cool! |
Perhaps that should just be documented as a requirement of the unsafe It would be nice if there could be an entirely safe API rather than the unsafely and unenforced lifetimes inherent in |
There are some other things I'd like to work on in Softbuffer, but I wouldn't really want to work on any non-trivial changes until this is merged. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few notes about Wayland impl.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The web implementation is LGTM.
Sorry to drop my 2c here a bit late to the party, but I was wondering why the original Surface::set_buffer()
method was completely replaced instead of just amending buffer_mut()
to Surface
.
The issue is that if a user is unable to avoid not copying the buffer, for example they receive the buffer already as a Vec
from somewhere else, if a platform doesn't support "no-copy" the user will be copying twice now: once from their buffer to the softbuffer
buffer, then softbuffer
will copy from it's buffer to the OS buffer.
This affects at least two Tier 1 platforms: X11 (sometimes) and MacOS. Additionally it affects Orbital (sometimes) and Web (in a weird way).
I propose to keep Surface::set_buffer()
and maybe even go a step further, return an error in buffer_mut()
if the surface can not be represented in a no-copy manner, making sure the user is aware and doesn't get the misconception that this is a no-copy operation.
This is off-topic for this PR, but originally I would have liked to introduce a new function in an extension trait for the Web target to be able to set the buffer in the correct format (RGBA vs 0RGB), avoiding the extra copying. This wouldn't play well with the missing Surface::set_buffer()
.
I saw in #17 that maybe there is the intention to introduce multiple Surface
formats, which would solve that problem in a different, probably better, way.
{ | ||
// Map window buffer | ||
let window_map = | ||
unsafe { OrbitalMap::new(window_fd, window_width * window_height * 4) } | ||
unsafe { OrbitalMap::new(self.window_fd(), window_width * window_height * 4) } | ||
.expect("failed to map orbital window"); | ||
|
||
// Window buffer is u32 color data in 0xAABBGGRR format |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jackpot51 sorry for my naivety here, but this comment suggests that the buffer taken and returned is partly reversed compared to what is expected by the rest of the library, ABGR vs 0RGB. Isn't that a problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, good point. In my testing it seemed like the colors where the same on all platforms, but something isn't right with the documentation here, at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any case the existing implementation isn't swapping components and this comment is already here, so this isn't something introduced in this PR. (Though if the format didn't match that might impact the possibility of no-copy on Orbital.)
Basically there are two advantages to removing it:
Arguably the crate is more intuitive with only one way to do things.
Usually For web... yeah, that's awkward if it can't support the same format that is used everywhere else.
I definitely don't agree on making In my opinion We could support both. It adds some complexity to the implementation, and we'll need to document to favor
We definitely at least need a way to chose between alpha and non-alpha modes. There are a lot of formats that could be supported, depending on backend. So what is worth supporting here and how much complexity is worth adding is up for debate. |
I wasn't aware of this. My motivation was the (potential) overhead when no-copy isn't available, so that's moot as soon as MacOS gets implemented. I think for Web we need a different solution anyway, which we can address later. |
In particular, macOS (and iOS) has something called We can also add back |
Updated to use |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use .get()
on NonZero
types, instead of u32::from
.
Great job, everyone! |
* On MacOS, the contents scale is updated when set_buffer() is called, to adapt when the window is on a new screen (#68). * **Breaking:** Split the `GraphicsContext` type into `Context` and `Surface` (#64). * On Web, cache the document in the `Context` type (#66). * **Breaking:** Introduce a new "owned buffer" for no-copy presentation (#65). * Enable support for multi-threaded WASM (#77). * Fix buffer resizing on X11 (#69). * Add a set of functions for handling buffer damage (#99). * Add a `fetch()` function for getting the window contents (#104). * Bump MSRV to 1.64 (#81).
WIP implementation of #40.
Currently this only has Wayland. It can be run with
cargo run --no-default-features --features wayland --example winit
.We should do some testing to see what impact it actually has.