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

[Merged by Bors] - Rework ViewTarget to better support post processing #6415

Closed
wants to merge 4 commits into from

Conversation

cart
Copy link
Member

@cart cart commented Oct 30, 2022

Objective

Post processing effects cannot read and write to the same texture. Currently they must own their own intermediate texture and redundantly copy from that back to the main texture. This is very inefficient.

Additionally, working with ViewTarget is more complicated than it needs to be, especially when working with HDR textures.

Solution

ViewTarget now stores two copies of the "main texture". It uses an atomic value to track which is currently the "main texture" (this interior mutability is necessary to accommodate read-only RenderGraph execution).

ViewTarget now has a post_process_write method, which will return a source and destination texture. Each call to this method will flip between the two copies of the "main texture".

let post_process = render_target.post_process_write();
let source_texture = post_process.source;
let destination_texture = post_process.destination;

The caller must read from the source texture and write to the destination texture, as it is assumed that the destination texture will become the new "main texture".

For simplicity / understandability ViewTarget is now a flat type. "hdr-ness" is a property of the TextureFormat. The internals are fully private in the interest of providing simple / consistent apis. Developers can now easily access the main texture by calling view_target.main_texture().

HDR ViewTargets no longer have an "ldr texture" with TextureFormat::bevy_default. They only have their two "hdr" textures. This simplifies the mental model. All we have is the "currently active hdr texture" and the "other hdr texture", which we flip between for post processing effects.

The tonemapping node has been rephrased to use this "post processing pattern". The blit pass has been removed, and it now only runs a pass when HDR is enabled. Notably, both the input and output texture are assumed to be HDR. This means that tonemapping behaves just like any other "post processing effect". It could theoretically be moved anywhere in the "effect chain" and continue to work.

In general, I think these changes will make the lives of people making post processing effects much easier. And they better position us to start building higher level / more structured "post processing effect stacks".


Changelog

  • ViewTarget now stores two copies of the "main texture". Calling ViewTarget::post_process_write will flip between copies of the main texture.

@cart cart added A-Rendering Drawing game state to the screen C-Usability A simple quality-of-life change that makes Bevy easier to use labels Oct 30, 2022
@cart cart added this to the Bevy 0.9 milestone Oct 30, 2022
Copy link
Member

@dataphract dataphract left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Very excited to delete like a third of my JFA code :D

crates/bevy_render/src/view/mod.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@irate-devil irate-devil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I barely comprehend any of the rendering stuff but the diffs look nice 🙈
Just one nit :)

crates/bevy_render/src/view/mod.rs Outdated Show resolved Hide resolved
main_textures: MainTargetTextures,
main_texture_format: TextureFormat,
/// 0 represents `texture_a`, 1 represents `texture_b`
main_texture: AtomicUsize,
Copy link
Contributor

@robtfm robtfm Oct 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we force post processing to use &mut ViewTarget? i'm not sure but it feels like the atomic here could mask issues with concurrent writers, where there's no guarantee the render passes would be in the same order as the post_process_write requests.
edit: looks like node processing is single threaded, so that's not a problem. then i guess it's atomic so that it can be edited without a mut ref. all good.

Copy link
Member Author

@cart cart Oct 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is currently valid. I would like to revisit what mutability might look like here though. There is a world where we choose to make node processing parallel. Thats one of the reasons we're restricting to &World in the first place (to make graph execution read-only).

I know a number of people (including myself) have explored the idea to move this stuff into systems. Still not sure how I feel about it, but it would allow more granular read/writes in a parallel context (force linear command encoding for post processing effects, by nature of the mutable access to ViewTarget, allow parallel command encoding for most other things, as long as the systems are read only).

@cart
Copy link
Member Author

cart commented Oct 31, 2022

bors r+

bors bot pushed a commit that referenced this pull request Oct 31, 2022
# Objective

Post processing effects cannot read and write to the same texture. Currently they must own their own intermediate texture and redundantly copy from that back to the main texture. This is very inefficient.

Additionally, working with ViewTarget is more complicated than it needs to be, especially when working with HDR textures. 

## Solution

`ViewTarget` now stores two copies of the "main texture". It uses an atomic value to track which is currently the "main texture" (this interior mutability is necessary to accommodate read-only RenderGraph execution). 

`ViewTarget` now has a `post_process_write` method, which will return a source and destination texture. Each call to this method will flip between the two copies of the "main texture".

```rust
let post_process = render_target.post_process_write();
let source_texture = post_process.source;
let destination_texture = post_process.destination;
```
The caller _must_ read from the source texture and write to the destination texture, as it is assumed that the destination texture will become the new "main texture".


For simplicity / understandability `ViewTarget` is now a flat type. "hdr-ness" is a property of the `TextureFormat`. The internals are fully private in the interest of providing simple / consistent apis. Developers can now easily access the main texture by calling `view_target.main_texture()`.

HDR ViewTargets no longer have an "ldr texture" with `TextureFormat::bevy_default`. They _only_ have their two "hdr" textures. This simplifies the mental model.  All we have is the "currently active hdr texture" and the "other hdr texture", which we flip between for post processing effects.

The tonemapping node has been rephrased to use this "post processing pattern". The blit pass has been removed, and it now only runs a pass when HDR is enabled. Notably, both the input and output texture are assumed to be HDR. This means that tonemapping behaves just like any other "post processing effect". It could theoretically be moved anywhere in the "effect chain" and continue to work.

In general, I think these changes will make the lives of people making post processing effects much easier. And they better position us to start building higher level / more structured  "post processing effect stacks".

---

## Changelog

- `ViewTarget` now stores two copies of the "main texture". Calling `ViewTarget::post_process_write` will flip between copies of the main texture.
@bors bors bot changed the title Rework ViewTarget to better support post processing [Merged by Bors] - Rework ViewTarget to better support post processing Oct 31, 2022
@bors bors bot closed this Oct 31, 2022
@mockersf mockersf added the hacktoberfest-accepted A PR that was accepted for Hacktoberfest, an annual open source event label Oct 31, 2022
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
# Objective

Post processing effects cannot read and write to the same texture. Currently they must own their own intermediate texture and redundantly copy from that back to the main texture. This is very inefficient.

Additionally, working with ViewTarget is more complicated than it needs to be, especially when working with HDR textures. 

## Solution

`ViewTarget` now stores two copies of the "main texture". It uses an atomic value to track which is currently the "main texture" (this interior mutability is necessary to accommodate read-only RenderGraph execution). 

`ViewTarget` now has a `post_process_write` method, which will return a source and destination texture. Each call to this method will flip between the two copies of the "main texture".

```rust
let post_process = render_target.post_process_write();
let source_texture = post_process.source;
let destination_texture = post_process.destination;
```
The caller _must_ read from the source texture and write to the destination texture, as it is assumed that the destination texture will become the new "main texture".


For simplicity / understandability `ViewTarget` is now a flat type. "hdr-ness" is a property of the `TextureFormat`. The internals are fully private in the interest of providing simple / consistent apis. Developers can now easily access the main texture by calling `view_target.main_texture()`.

HDR ViewTargets no longer have an "ldr texture" with `TextureFormat::bevy_default`. They _only_ have their two "hdr" textures. This simplifies the mental model.  All we have is the "currently active hdr texture" and the "other hdr texture", which we flip between for post processing effects.

The tonemapping node has been rephrased to use this "post processing pattern". The blit pass has been removed, and it now only runs a pass when HDR is enabled. Notably, both the input and output texture are assumed to be HDR. This means that tonemapping behaves just like any other "post processing effect". It could theoretically be moved anywhere in the "effect chain" and continue to work.

In general, I think these changes will make the lives of people making post processing effects much easier. And they better position us to start building higher level / more structured  "post processing effect stacks".

---

## Changelog

- `ViewTarget` now stores two copies of the "main texture". Calling `ViewTarget::post_process_write` will flip between copies of the main texture.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Usability A simple quality-of-life change that makes Bevy easier to use hacktoberfest-accepted A PR that was accepted for Hacktoberfest, an annual open source event
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants