vulkano-rs / vulkano

Safe and rich Rust wrapper around the Vulkan API
Apache License 2.0
4.56k stars 437 forks source link

Black screen when blitting onto swapchain image 0 #1378

Open Rua opened 4 years ago

Rua commented 4 years ago

This is quite a weird issue, so I hope I explain it well enough.

I want to set up my rendering to draw to an offscreen image, and then blit this image onto the swapchain image. To do this, I set up a series of command buffers right after creating the swapchain and attachment images, one for each swapchain image, generated with the following code:

let blit_command_buffers = images.iter()
    .map(|target_image| {
        let mut builder = AutoCommandBufferBuilder::primary(
            device.clone(),
            graphics_queue.family(),
        )?;
        builder.blit_image(
            colour_attachment.clone(),
            [0, 0, 0],
            [width as i32, height as i32, depth as i32],
            0,
            0,
            target_image.clone(),
            [0, 0, 0],
            [width as i32, height as i32, depth as i32],
            0,
            0,
            1,
            vulkano::sampler::Filter::Nearest,
        )?;
        Ok(Arc::new(builder.build()?))
    })
    .collect::<anyhow::Result<Vec<_>>()?;

In my draw loop, I build and execute a draw command buffer (draw_commands), and acquire a swapchain image. The futures are then submitted:

let draw_future = draw_commands.execute(graphics_queue.clone())?;
let (image_num, suboptimal, swapchain_future) = acquire_next_image(swapchain.clone(), None)?;
draw_future
    .join(swapchain_future)
    .then_execute(
        graphics_queue.clone(),
        blit_command_buffers[image_num].clone(),
    )?
    .then_swapchain_present(
        graphics_queue.clone(),
        swapchain().clone(),
        image_num,
    )
    .then_signal_fence_and_flush()?
    .wait(None)?;

All submissions happen on the same queue, so I don't think semaphores would be needed. The command buffer that blits the framebuffer onto the swapchain image is executed after both the drawing and the swapchain acquire.

When doing it this way, I get flickering every few frames. I've determined that whenever swapchain image 0 is acquired, the presented frame is black. The other swapchain images are rendered properly. The odd part is that if I regenerate blit_command_buffers using the first code, immediately before the second code, there is no flickering, all frames are normal. There is no flickering either if I regenerate the command buffers after the present code if image_num == 0 only. The flickering only happens if the original command buffers are used, which are generated once on swapchain (re)creation. So I'm wondering if it has to do with the original state of the swapchain images before any rendering is done. In any case, it's a real mystery to me.

AustinJ235 commented 4 years ago

I am guessing that somewhere the barriers are not being inserted correctly, or you are not using the correct functions. Personally I haven't played with reusing command buffers. If possible I would check to see if there is any validations errors that are popping up.

Things you could try is using another variant an AutoCommandBufferBuilder constructor, but I don't think that'll help. Worth a try those fairly straight forward to do. Are you running cleanup_finished() on the GpuFuture between frames? Maybe the resources are not being let go before you return when you return back to the start. Another not so optimal thing to try would to add a then_signal_fence_and_flush after the then_execute to force some sorta of sync before the present as maybe the command isn't properly finished, before it goes to present.

In any case I would imagine that there would be a validation error.

Rua commented 4 years ago

There are no validation errors, even when I set them to display absolutely everything possible. Just some information about available device extensions at load time, which probably isn't relevant.

Using another AutoCommandBufferBuilder constructor had no effect, the problem still occurs when I use primary_simultaneous_use. I don't use cleanup_finished because I'm waiting for a fence at the end of each frame, which consumes the future.

Calling then_signal_fence_and_flush()?.wait(None)? on draw_future has no effect. If I call it on swapchain_future it panics with this backtrace (non-Vulkano parts omitted):

thread 'main' panicked at 'assertion failed: future.queue().is_some()', <::std::macros::panic macros>:2:4

12: vulkano::sync::future::fence_signal::then_signal_fence
             at ./<::std::macros::panic macros>:2
13: vulkano::sync::future::GpuFuture::then_signal_fence
             at /home/rua/.cargo/registry/src/github.com-1ecc6299db9ec823/vulkano-0.19.0/src/sync/future/mod.rs:235
14: vulkano::sync::future::GpuFuture::then_signal_fence_and_flush
             at /home/rua/.cargo/registry/src/github.com-1ecc6299db9ec823/vulkano-0.19.0/src/sync/future/mod.rs:246

Calling it on the joined future freezes the program.

AustinJ235 commented 4 years ago

One other think I can think of is increasing the image count of the swapchain. In vulkan it is good practice to run 1 frame over the minimal image count.

If you could provide a complete minimal example that would also be useful.

Rua commented 4 years ago

I've set up a repository at https://github.com/Rua/flicker-demo with a relatively minimal (in Vulkan terms, anyway, hah) example that displays the behaviour for me. There are no pipelines and no drawing, as it appears that the clear colour of the render pass is enough to show the flicker for me. The code is a bit of a mess, as it was ripped out of a larger project that is itself a work in progress, but hopefully it's understandable.

Note that present_commands2 is unused. If you change present_commands on line 207 to it, the flickering goes away for me.

medicalwei commented 4 years ago

I tried the above test case, and found that when executing present_commands then present_commands2 in draw_future, it does blink. However, as she suggested that swapping present_commands in place with present_commands2, the blinking does stop.

I am running Debian Sid with Intel Graphics 620, mesa-vulkan-driver 20.0.7, Linux kernel 5.6.0-2

FreeFull commented 4 years ago

With the above test case, I don't see any flicker without having to use any workarounds. I am running Arch Linux, with the 5.6.15 Linux kernel, Haswell graphics. I have tested with both X11 and the sway wayland compositor, and didn't see any flicker with either of them.

Device: Mesa DRI Intel(R) HD Graphics 4400 (HSW GT2) (0xa16)
Version: 20.0.7
Rua commented 4 years ago

My own environment:

AustinJ235 commented 4 years ago

I have replicated the issue on linux. Windows had no issues. Still looking for problems.

AustinJ235 commented 4 years ago

Looking like this could be a bug in the radeon-vulkan driver in mesa. I have tried a few other things with no prevail. Using amdvlk however doesn't experience this behavior.

In terms of what I am running:

Rua commented 4 years ago

@medicalwei Also got the flickering though, and they have Intel graphics.

jglauche commented 4 years ago

No flicker for me on my x230 i7 running kernel 5.6.15-1-MANJARO graphics: Intel(R) HD Graphics 4000 (IVB GT2) (ID: 0) Intel open-source Mesa driver Mesa 20.0.7 using xorg

nbraud commented 4 years ago

Cannot replicate the flickering here either (Debian testing, Intel Ivy Bridge, on wayland) :

$ inxi -bG
System:    Host: neon.citronna.de Kernel: 5.6.0-2-amd64 x86_64 bits: 64 Desktop: sway 1.4 
           Distro: Debian GNU/Linux bullseye/sid 
Machine:   Type: Laptop System: LENOVO product: 23252QG v: ThinkPad X230 
           Mobo: LENOVO model: 23252QG v: ThinkPad X230
           BIOS: coreboot v: CBET4000 4.8-883-gd308ed37bc date: 07/26/2018 
CPU:       Dual Core: Intel Core i5-3320M type: MT MCP speed: 1285 MHz min/max: 1200/3300 MHz 
Graphics:  Device-1: Intel 3rd Gen Core processor Graphics driver: i915 v: kernel 
           Display: server: X.Org 1.20.8 driver: modesetting unloaded: fbdev,vesa 
           resolution: 1366x768~60Hz 
           OpenGL: renderer: Mesa DRI Intel Ivybridge Mobile v: 4.2 Mesa 19.3.3 
AustinJ235 commented 4 years ago

Interesting. So looking potentially at an issue with newer intel and amd vulkan drivers. I don't think it would be anything vulkano wise, pretty much ruled out everything.


Distro       Kernel  Desktop            Mesa    Card        Issue
---------------------------------------------------------------------
Mint 19.3    5.3.0   Cinnamon 4.4.8 (xorg)  19.2.8  RX 480      Yes
Debian Sid   5.6.0   ?                      20.0.7  Intel 620   Yes
Arch         5.6.15  ? (wayland)            20.0.7  Intel 4400  No
Arch         5.6.16  Openbox 3.6.1 (xorg)   20.2.0  Vega 56     Yes
Manjaro      5.6.15  ? (xorg)               20.0.7  Intel 4000  No
Debian Sid   5.6.0   Sway (wayland)         19.3.3  Intel Ivy   No
AustinJ235 commented 4 years ago

I did rule out that the begin_render_pass and blit_image weren't directly the culprits. Using a clear_image instead of a begin_render_pass and a copy_image instead of blit_image. I believe I tried clear_image directly on the target image and had issues.

Edit I also tried wayland with gnome to rule wayland out. Seems it is just the amd cards and newer intel graphics. I believe these drivers do share a good portion of code.

Rua commented 4 years ago

I tried it on my laptop, and no flickering there. Using the same OS as on my desktop.

System:
  Host: rua-ThinkPad-X250 Kernel: 5.3.0-40-generic x86_64 bits: 64 
  Desktop: Cinnamon 4.4.8 Distro: Linux Mint 19.3 Tricia 
Machine:
  Type: Laptop System: LENOVO product: 20CLS45J00 v: ThinkPad X250 
  Mobo: LENOVO model: 20CLS45J00 v: SDK0E50510 WIN serial: <root required> 
  UEFI: LENOVO v: N10ET59W (1.38 ) date: 08/15/2019 
CPU:
  Dual Core: Intel Core i5-5300U type: MT MCP speed: 798 MHz 
  min/max: 500/2900 MHz 
Graphics:
  Device-1: Intel HD Graphics 5500 driver: i915 v: kernel 
  Display: x11 server: X.Org 1.20.5 driver: modesetting unloaded: fbdev,vesa 
  resolution: 1366x768~60Hz 
  OpenGL: renderer: Mesa DRI Intel HD Graphics 5500 (Broadwell GT2) 
  v: 4.5 Mesa 19.2.8 
AustinJ235 commented 4 years ago

Well. If I set the storage usage on the attachment image the flickering goes away.

Rua commented 4 years ago

I can confirm that too, the same happens with me.

medicalwei commented 4 years ago

Can also confirm that the storage usage on colour_attachment stops the flicker.