-
Notifications
You must be signed in to change notification settings - Fork 2
Refactor rendering crate to clarify primary Processing API #34
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
Conversation
|
So on graphics::readback we queue up a command to copy the texture to the buffer. then we wait for that to complete yes? and in the example the way you have it, is you're doing the readback after it's done with drawing not while it's drawing? what would happen if you did a readback before EDIT: Ah. OK. Right. This all goes into bevy renderer world. |
| #[derive(Component)] | ||
| #[relationship(relationship_target = TransientMeshes)] | ||
| pub struct BelongsToSurface(pub Entity); | ||
| pub struct BelongsToGraphics(pub Entity); |
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.
as we start to solidify all of this, it could be nice to have a diagram outlining the relationships of our bevy entities
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.
yeah, for sure, in ecs terms this is an "archetype" i.e. the table that a given entity lives in and which components it has
Yes, basically we store a staging buffer for every texture to make available to copy into and map into CPU address space. This is typically a non-blocking operation and the code here makes it blocking by waiting on a channel.
Short answer, yes. You can readback whenever. As long as you flush first. Our Long answer: So, deep within the Bevy renderer, there's something called The camera's When users manually update pixels on the CPU, we write those pixels into the main view target texture, i.e. the unsampled MSAA resolve target, in what's effectively a buffer to texture copy. However, this presents a problem, because when MSAA is enabled, this main texture is just the resolve target not the render color attachment. In other words, the actual "source of truth" is the multi-sampled color attachment. But you can't write directly into a sampled texture because it's not just pixels it's sub-samples per logical pixel. Render engines handle this by doing something called MSAA writeback at the beginning of a new frame/render graph pass, which basically ensures that the current state of the "main" texture, i.e. resolve target, is "written back" into the sampled color attachment. In other words, this is a post-process write where we blit the previous main texture into the new ping-pong'd sampled texture, aka a "reverse resolve" where we expand the single sampled texture (the one we can manually write into) back into sub-samples. Whew! MSAA makes everything kinda complicated! But the tl;dr here is that "flush" is necessary in order to make sure that things are "settled" - that all our pending draw commands have been issued and that all our manual writes have been materialized such that they're in the right place. This is... somewhat problematic for topline performance! Outside of the blocking nature of readback, it also means that we have to do a lot of work (multiple redundant passes) in order to present a single frame. This is why it's inefficient. |
| let pixel_size = match texture_format { | ||
| TextureFormat::R8Unorm => 1, | ||
| TextureFormat::Rg8Unorm => 2, | ||
| TextureFormat::Rgba8Unorm | ||
| | TextureFormat::Bgra8Unorm | ||
| | TextureFormat::Rgba16Float | ||
| | TextureFormat::Rgba32Float => 4, | ||
| _ => return Err(ProcessingError::UnsupportedTextureFormat), | ||
| }; |
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.
we love this obviously
catilac
left a comment
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.
yay this all works. thanks for answering my million questions
This PR makes a significant number of changes to the current project with the goal of pulling apart the different API objects in the core Processing API and implementing the rest of basic rendering functionality. As such, it may be difficult to review as a single unit. Let's discuss these individual changes.
processing_render/src/lib.rsto their own modules. It's nice to keeplib.rsas the entry point to all our functionality, but the implementations should live somewhere else.surfaceno longer owns everything and is demoted to the equivalent of a BevyRenderTarget.graphicsis made explicit. This is aCamerain Bevy and the owner of rendering commands. Implicitly has a relationship to a surface.PImagenaming convention. This isn't idiomatic in Rust and is very Java-ish. I went back and forth here. The Rust-y thing would be to call thisProcessingImage, but that's kind of verbose. The even more Rust-y thing would just to be to rely on the module to disambiguate. Our implementers will importprocessing::Image. The downside here is that many of these names conflict with other stuff. I think that's okay as it's mostly in our lib.