-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
more camera output options #7490
Conversation
Example |
crates/bevy_core_pipeline/Cargo.toml
Outdated
@@ -31,3 +31,4 @@ bevy_utils = { path = "../bevy_utils", version = "0.9.0" } | |||
serde = { version = "1", features = ["derive"] } | |||
bitflags = "1.2" | |||
radsort = "0.1" | |||
wgpu = "0.15.0" |
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.
newline
/// Flush the current render results to the [`RenderTarget`]. | ||
/// The blend mode is used to combine results with previous contents of the target. Typically the first flushing | ||
/// camera writing to a target will use `Flush(None)` to clear the target and write the current render results. | ||
/// If multiple flushing cameras are used, later cameras may prefer to use `Flush(Some(BlendState::ALPHA_BLENDING))` | ||
/// to combine render results with previously flushed results. | ||
/// if a camera uses `Flush`, the next camera on the the same target should clear the internal render results with | ||
/// `ClearColorConfig::Custom(Color::NONE)` to avoid double writing of the first results on the next flush. | ||
Flush(Option<wgpu::BlendState>), | ||
/// Keep the current render results internally. A later camera must output with `Flush` for any results to be output. | ||
/// This is useful for combining the results of several cameras before applying post-processing to the full set of results. | ||
/// If a camera uses `Retain`, the next camera on the same target should make sure NOT to clear the render results by | ||
/// using `ClearColorConfig::None`, else they will be discarded. | ||
Retain, |
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.
I feel like the names don't make obvious what the modes are. As I was reading various parts of the PR I wasn't sure if Flush was going to mean something like discarding or writing out what is present. Similarly Retain feels like it could mean keep the results (as in write them out) when compared to Flush, if Flush were understood to mean discard.
How about renaming Flush
to Blend
or perhaps Combine
(I prefer Blend
)?
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.
hmm... i was trying to draw an analogy with stream flushing (like stdout). my problem with combine and blend is that they don't really make you feel like you need to do it to get results. but its true that flush can also mean "clear" so it isn't great.
maybe Finish
and Continue
..?
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, the naming isn't intuitive.
Finish
and Continue
are clearer, but continue still seems relatively unspecific.
Maybe the combination of Finish
and Retain
(or even Gather
?) might be an option.
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.
changed to Finish
and Retain
Adding this to 0.10 as it looks to clear up quite a few camera composition and post-processing issues. |
/// Flush the current render results to the [`RenderTarget`]. | ||
/// The blend mode is used to combine results with previous contents of the target. Typically the first flushing | ||
/// camera writing to a target will use `Flush(None)` to clear the target and write the current render results. | ||
/// If multiple flushing cameras are used, later cameras may prefer to use `Flush(Some(BlendState::ALPHA_BLENDING))` | ||
/// to combine render results with previously flushed results. | ||
/// if a camera uses `Flush`, the next camera on the the same target should clear the internal render results with | ||
/// `ClearColorConfig::Custom(Color::NONE)` to avoid double writing of the first results on the next flush. | ||
Flush(Option<wgpu::BlendState>), | ||
/// Keep the current render results internally. A later camera must output with `Flush` for any results to be output. | ||
/// This is useful for combining the results of several cameras before applying post-processing to the full set of results. | ||
/// If a camera uses `Retain`, the next camera on the same target should make sure NOT to clear the render results by | ||
/// using `ClearColorConfig::None`, else they will be discarded. | ||
Retain, |
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, the naming isn't intuitive.
Finish
and Continue
are clearer, but continue still seems relatively unspecific.
Maybe the combination of Finish
and Retain
(or even Gather
?) might be an option.
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.
I am not super familiar with the camera and postprocessing code, but the code quality is great and the feature is easy enough to understand from my point of view. LGTM.
This feels a bit weird to me for a number of reasons. Took me awhile to sort out why it felt wrong, but I think I finally consolidated my thoughts:
This also doesn't seem to fix #7361. I think I did the recommended config correctly? I think this is my preferred solution (starting from the current state on
This way, whenever you access the For example:
|
this is made trickier with msaa. after post-processing we are on a non-msaa texture and the next pass wants to start from the multisampled texture so a copy-back is really required. i thought doing the simple thing and always copying back was the easiest to follow (and this will need reworking if/when we do msaa-per-camera in future anyway).
in this case you don't want to set
with msaa i think copy back is required
i also changed the upscaling to
happy to remove that behaviour if you prefer. i added it since the correct choice isn't always obvious (maybe we should rename |
Arg yeah I completely left that out of my mental model. My bad! Definitely complicates things. I'll ponder this for a bit and get back to you.
That does indeed work!
Hmm that makes sense. I think making this explicit (and i guess defaulting to overwrite to make the normal case work) might be the move. I'll add it to the list of constraints that I missed and get back to you :) |
My non-serious suggestion is that we remove MSAA in the interest of pipeline purity :) |
Ok so I've been experimenting / poking / prodding / thinking today and it definitely does seem like writeback is required (for MSAA). Here is my "next" proposal:
#[derive(Debug, Clone, Copy)]
pub enum CameraOutputMode {
/// Writes the camera output to configured render target.
Write {
/// The blend state that will be used by the pipeline that writes the intermediate render textures to the final render target texture.
blend_state: Option<BlendState>,
/// The color attachment load operation that will be used by the pipeline that writes the intermediate render textures to the final render
/// target texture.
color_attachment_load_op: wgpu::LoadOp<wgpu::Color>,
},
/// Skips writing the camera output to the configured render target. The output will remain in the
/// Render Target's "intermediate" textures, which a camera with a higher order should write to the render target
/// using [`CameraOutputMode::Write`]. The "skip" mode can easily prevent render results from being displayed, or cause
/// them to be lost. Only use this if you know what you are doing!
Skip,
}
I have everything but (1) implemented, but I'm leaving for the rest of the night (and all of tomorrow) starting now, so if anyone beats me to the final impl I wont mind. If we go with my branch I'll add @robtfm as a co-author as this is largely just a reframing of the work done here / theres no way I would have come up with this on my own without way more time invested. |
Also this is just a proposal. If I've (once again) missed something important please let me know. Very open to feedback! |
Closing in favor of #7671 |
# Objective Alternative to #7490. I wrote all of the code in this PR, but I have added @robtfm as co-author on commits that build on ideas from #7490. I would not have been able to solve these problems on my own without much more time investment and I'm largely just rephrasing the ideas from that PR. Fixes #7435 Fixes #7361 Fixes #5721 ## Solution This implements the solution I [outlined here](#7490 (comment)). * Adds "msaa writeback" as an explicit "msaa camera feature" and default to msaa_writeback: true for each camera. If this is true, a camera has MSAA enabled, and it isn't the first camera for the target, add a writeback before the main pass for that camera. * Adds a CameraOutputMode, which can be used to configure if (and how) the results of a camera's rendering will be written to the final RenderTarget output texture (via the upscaling node). The `blend_state` and `color_attachment_load_op` are now configurable, giving much more control over how a camera will write to the output texture. * Made cameras with the same target share the same main_texture tracker by using `Arc<AtomicUsize>`, which ensures continuity across cameras. This was previously broken / could produce weird results in some cases. `ViewTarget::main_texture()` is now correct in every context. * Added a new generic / specializable BlitPipeline, which the new MsaaWritebackNode uses internally. The UpscalingPipelineNode now uses BlitPipeline instead of its own pipeline. We might ultimately need to fork this back out if we choose to add more configurability to the upscaling, but for now this will save on binary size by not embedding the same shader twice. * Moved the "camera sorting" logic from the camera driver node to its own system. The results are now stored in the `SortedCameras` resource, which can be used anywhere in the renderer. MSAA writeback makes use of this. --- ## Changelog - Added `Camera::msaa_writeback` which can enable and disable msaa writeback. - Added specializable `BlitPipeline` and ported the upscaling node to use this. - Added SortedCameras, exposing information that was previously internal to the camera driver node. - Made cameras with the same target share the same main_texture tracker, which ensures continuity across cameras.
# Objective Alternative to bevyengine#7490. I wrote all of the code in this PR, but I have added @robtfm as co-author on commits that build on ideas from bevyengine#7490. I would not have been able to solve these problems on my own without much more time investment and I'm largely just rephrasing the ideas from that PR. Fixes bevyengine#7435 Fixes bevyengine#7361 Fixes bevyengine#5721 ## Solution This implements the solution I [outlined here](bevyengine#7490 (comment)). * Adds "msaa writeback" as an explicit "msaa camera feature" and default to msaa_writeback: true for each camera. If this is true, a camera has MSAA enabled, and it isn't the first camera for the target, add a writeback before the main pass for that camera. * Adds a CameraOutputMode, which can be used to configure if (and how) the results of a camera's rendering will be written to the final RenderTarget output texture (via the upscaling node). The `blend_state` and `color_attachment_load_op` are now configurable, giving much more control over how a camera will write to the output texture. * Made cameras with the same target share the same main_texture tracker by using `Arc<AtomicUsize>`, which ensures continuity across cameras. This was previously broken / could produce weird results in some cases. `ViewTarget::main_texture()` is now correct in every context. * Added a new generic / specializable BlitPipeline, which the new MsaaWritebackNode uses internally. The UpscalingPipelineNode now uses BlitPipeline instead of its own pipeline. We might ultimately need to fork this back out if we choose to add more configurability to the upscaling, but for now this will save on binary size by not embedding the same shader twice. * Moved the "camera sorting" logic from the camera driver node to its own system. The results are now stored in the `SortedCameras` resource, which can be used anywhere in the renderer. MSAA writeback makes use of this. --- ## Changelog - Added `Camera::msaa_writeback` which can enable and disable msaa writeback. - Added specializable `BlitPipeline` and ported the upscaling node to use this. - Added SortedCameras, exposing information that was previously internal to the camera driver node. - Made cameras with the same target share the same main_texture tracker, which ensures continuity across cameras.
Objective
Solution
CameraOutputMode
to theCamera
struct. defines whether the camera retains it's results or flushes them to the output.CameraOutputMode::Default
will retain results unless the camera is last, in which case it will flush them.Retain
, which fixes some issues with post-processing steps being droppedCameraChainPosition
inextract_cameras
, which describes whether a camera is first, first after a flush or neither of those, andfix #7435
fix #7361 (you would need to add a Flush to the first camera, so that bloom on the second camera doesn't affect the first camera's results) EDIT: and remove the
ClearColorConfig::None
from the second camera so it defaults to transparent clearfix #5721
note - if you use multiple overlapping cameras in Retain mode, you should disable FXAA and tonemapping (and any other fullscreen effects) on all but the last one.
todo:
Migration Guide
this should maintain all existing behaviour - i think if it worked before it'll still work now. On secondary cameras, adding 'ClearColorConfig::None` is no longer required but is not harmful.