Add WriteOnly type to replace giving &mut [u8] access to mapped buffers.#9042
Add WriteOnly type to replace giving &mut [u8] access to mapped buffers.#9042kpreid wants to merge 2 commits intogfx-rs:trunkfrom
WriteOnly type to replace giving &mut [u8] access to mapped buffers.#9042Conversation
|
Ok I'm going off the generated docs so these won't be comments on the code but I have some questions. Overall trust your opinion more than mine.
|
As I mentioned in the PR description, there are a couple already. I think that if we put effort into separate versioning it would make sense to see if we can contribute to one of those efforts instead of publishing yet another variation — and if not, we get to tweak it to be maximally ergonomic for writing into
I’ve never seen such a situation, and if there was one, I’d expect it to be acting on a slice rather than a
Not just
|
madsmtm
left a comment
There was a problem hiding this comment.
Re in wgpu vs. outref/wref, an option in between could be to make a new crate (possibly in a separate gfx-rs repo?) - that'd make it possible to tune the API exactly for wgpu's needs, while also making it easier to test with Miri.
cwfitzgerald
left a comment
There was a problem hiding this comment.
This is insanely high quality stuff. I definitely think this is the right approach, have one nit. For miri, we could also enable just the tests from naga/wgpu/wgpu-core/wgpu-hal initially, as those don't require the GPU at all and don't take much time to run.
2f196ef to
448f31e
Compare
|
I stayed up entirely too late and I may regret this, but there are tests now, and I think this is basically ready for review, though definitely not ready for merging. |
8334940 to
0c6e5dc
Compare
| /// | ||
| /// [mapped]: Buffer#mapping-buffers | ||
| #[track_caller] | ||
| pub fn get_mapped_range(&self) -> BufferView { |
There was a problem hiding this comment.
Need to add (if one doesn’t already exist) a test checking that one cannot get a read-access BufferView to a write mapping. Or if that is required to be possible by the spec, then things still might be fine, but some of the documentation I added needs to be changed.
There was a problem hiding this comment.
Per exploratory testing, and discussion in maintainers meeting:
- Currently, you can
get_mapped_range()(read access) on aMapMode::Write - I am told that writes to write-combining memory can effectively "show up randomly later" to reads
- Therefore, it is unsound to expose
&[u8]pointing to write-combining memory- (Unless there is some kind of fence / cache flush that could be used? But we don't need that anyway.)
- Therefore, we must prohibit
get_mapped_range()working on that memory. - The simplest API surface we can provide is to say that
get_mapped_range()never works on aMapMode::Writemapping under any conditions.- This will also simplify the user-facing model because reading a write mapping never was guaranteed to give you meaningful data.
I will update this PR to include a commit that makes this change.
`WriteOnly<'a, T>` is a custom smart pointer which is stricter than `&'a mut [T]` in that it only allows writing data and not reading it. This will be part of the fix for <gfx-rs#8897>. This commit only introduces the public type and does not use it.
Fixes <gfx-rs#8897>. When accessing a buffer for writing, do not expose (or internally create) any `&'a mut [u8]` references to that memory, so as to avoid exposing write-combining memory that might visibly misbehave in atomic operations. Instead, expose the new pointer type `WriteOnly<'a, [u8]>` which offers only write operations. This can be sliced and reborrowed, allowing it to be used in most ways which `&mut [u8]` would be, hopefully with near-zero overhead. This pointer type might also allow users to opt in to uninitialized memory for performance, while confining the consequences to GPU UB rather than Rust UB. However, that is a future possibility and is not implemented in this commit other than as a consideration in defining the API of the `WriteOnly` type.
Connections
Fixes #8897.
Description
When accessing a buffer for writing, do not expose (or internally create) any
&'a mut [u8]references to that memory, so as to avoid exposing write-combining memory that might visibly misbehave in atomic operations. Instead, expose a new pointer typeWriteOnly<'a, [u8]>which offers only write operations. This can be sliced and reborrowed, allowing it to be used in most ways which&mut [u8]would be, hopefully with near-zero overhead.This pointer type might also allow users to opt in to uninitialized memory for performance, while confining the consequences to GPU UB rather than Rust UB. However, that is a future possibility and is not implemented in this PR other than as a consideration in defining the API of the
WriteOnlytype.There are already published libraries that implement a write-only pointer type, such as
wref,outref; however, they are lacking in operations like chunking andIntoIteratorwhich I believe are necessary to provide reasonable ergonomics for our users’ use cases. An alternative to this PR’s unsafe code would be to contribute changes to one of those libraries to meet our needs.Testing
This PR has near-complete test coverage for the
WriteOnlytype through a mix of doctests and#[test]s. These tests are run under Miri in a new CI job.Squash or Rebase?
Rebase
Checklist
cargo fmt.taplo format.cargo clippy --tests. If applicable, add:--target wasm32-unknown-unknowncargo xtask testto run tests.CHANGELOG.mdentry.