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

Unexpected texture clears when using camera-driven rendering (minimal not working example included). #6051

Open
bzm3r opened this issue Sep 21, 2022 Discussed in #6041 · 6 comments
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior

Comments

@bzm3r
Copy link
Contributor

bzm3r commented Sep 21, 2022

Bevy version

0.8

Bug Information

Here's the minimal not working example.

bevy_pancam is enabled, so you should be able to drag the camera around, but we suggest just maximizing the window upon startup, in order to see everything clearly.

The basic setup here is: there's a large texture (the accumulation texture). We render into small squares (tile) of the accumulation texture sequentially. The accumulation texture has ClearColorConfig::None, which should in the background trigger a WGPU LoadOp::Load.

Every so often, we skip rendering a tile. The problem is that: when this skip occurs, the accumulation texture is cleared entirely.

A little more detail:

  1. every tick, we check to see if an event to draw a tile has been received (initially we send one such event, to start off the process);

  2. if we are asked to draw stuff into a tile: we render some rects using bevy_prototype_lyon by using a camera targetting a 4096 x 4096 texture (the hi res image);

  3. we take the 4096x4096 texture, and give it as a input (using Materials) to another camera which uses a viewport to target into TILE_SIZE x TILE_SIZE (where TILE_SIZE = 64) region of a large accumulation texture (here some downscaling happens); crucially, we queue sending of a rendering complete signal from the render device

  4. if a render complete signal was received we set is_active on the cameras responsible for rendering to false, and we write a render complete event

  5. we check to see if a render complete event was written; if it was, we send the the next "draw a tile" event.

We used RenderDoc to see what is happening during a skip. It seems that an unnecessary texture clear is called. But we are not yet fully at home in RenderDoc, so perhaps are not getting as much info out of it as we might be able to.

We tried understanding the Bevy code to see where in the "lifecycle" of an Image the corresponding Texture might be cleared, but we found it very hard to trace the "lifecycle" of an Image and its corresponding Texture to figure this out.

We have been stumped by this for a while 😖

Any of the following would be welcome:

  • ideas on why the texture clear is happening, or where it is happening?

  • ideas on what we else we could try?

  • suggestions on what we can do to make the minimal not-working example easier to work with?

  • thoughts on whether you would like to see us upload RenderDoc captures?

@colepoirier colepoirier added C-Bug An unexpected or incorrect behavior A-Rendering Drawing game state to the screen labels Sep 21, 2022
@BorisBoutillier
Copy link
Contributor

BorisBoutillier commented Sep 23, 2022

I am not a renderer expert at all, but I have played with your example, first to reproduce the issue , than to do some 'random' changes to see what happens.

I have been able to make the example work (I think) with the following change, around camera.is_active

        info!("RENDERING DONE");
        for mut cam in hires_cam_q.iter_mut() {
            cam.is_active = true;
        }

        for mut cam in accumulation_cam_q.iter_mut() {
            cam.is_active = true;
            cam.viewport = Some(Viewport {
                physical_position: UVec2::new(0, 0),
                physical_size: UVec2::new(1, 1),
                ..default()
            });
        }

It seems that the texture cleaning is in relation ( but complex) with the reactivation of camera, my change just keep all camera active, and for the accumulation camera render to a single point when was expected to be inactive

Does not explain anything at all, but that's all I have for today.
I'll continue to play with this example tomorrow and hopefully dig a bit further, on what is effectively happening.
On my side I am using that to learn a bit more about bevy :)

@BorisBoutillier
Copy link
Contributor

Digging a bit further I have found the culprit, even if not yet sure of the exact reason ( is it expected behaviour or bug).

What is messing with your texture is the MSAA, default bevy behaviour is to have MSAA 4x, if I remove MSAA in your example it behaves as expected ( I think).
To remove MSAA you need to add the following line during your App creation

.insert_resource( Msaa { samples: 1 } )

@bzm3r
Copy link
Contributor Author

bzm3r commented Sep 25, 2022

@Bobox214 words...cannot...describe... thank you for helping us understand this, even if it's first steps, this is the most progress we have seen in a while

@BorisBoutillier
Copy link
Contributor

Happy to have helped a bit !

I won't be able to go further, I have not seen anything suspicious on the bevy side, and wonder if the issue is on the wgpu.
I am reaching my capabilities and knowledge here.

I think that this is clearly related to msaa and probably the second texture needed for this feature. But why ?, I have not found.

@bzm3r
Copy link
Contributor Author

bzm3r commented Oct 2, 2022

Happy to have helped a bit !

I won't be able to go further, I have not seen anything suspicious on the bevy side, and wonder if the issue is on the wgpu. I am reaching my capabilities and knowledge here.

I think that this is clearly related to msaa and probably the second texture needed for this feature. But why ?, I have not found.

@Bobox214 I am curious to know: what made you think about MSAA as being a possible culprit?

@BorisBoutillier
Copy link
Contributor

I found out this by doing some code debugging.
Here was the process:

  1. I had quickly found that the bug was in relation with camera is_active state toggling, by just playing/modifying your code.
    As keeping the camera is_active allowed to workaround the bug.
  2. I then used a local version of bevy to modify places where camera is_active is checked.
    One is in crates/bevy_core_pipeline/src/core_2d/mod.rs, but is not in relation to the issue, as always executing the code, independently of is_active does not solve the issue.
    The second one is in crates/bevy_render/src/camera/camera.rs in the extract_camera system, where camera information is extracted for the render world when it is active.
  3. Looking where ExtractedCamera component is used, I ended in crates/bevy_render/src/view/mod.rs where there is a different behaviour depending on msaa.samples, particularly the creation of a new texture.
    And wondering if this was messing around with the main texture I just tested if desabling msaa was solving the issue, which it did.

Now further debugging in bevy, it seems there is nothing wrong done. Or anything I could pinpoint before calling wgpu draw calls.
And as Msaa is handled by wgpu I did not went further in debugging wgpu behaviour itself for this issue.

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-Bug An unexpected or incorrect behavior
Projects
None yet
Development

No branches or pull requests

3 participants