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

Project throwing "screen_prepare_for_drawing: Unable to acquire framebuffer" error when resizing game window (Nvidia, Linux) #94104

Closed
DraconicMentalist opened this issue Jul 8, 2024 · 10 comments · Fixed by #94135

Comments

@DraconicMentalist
Copy link

DraconicMentalist commented Jul 8, 2024

Tested versions

System information

Arch Linux - Godot 4.3 beta 2 - Vulkan (Forward+) - NVIDIA GeForce RTX 3090 (proprietary driver 555.58.02) - Cinnamon (X11)

Issue description

As the issue title says, my game is throwing an error when I attempt to resize the game window:

E 0:00:02:0776   screen_prepare_for_drawing: Unable to acquire framebuffer.
  <C++ Error>    Condition "framebuffer.id == 0" is true. Returning: FAILED
  <C++ Source>   servers/rendering/rendering_device.cpp:3503 @ screen_prepare_for_drawing()

The debugger quickly fills with this error every time the window is resized.

Steps to reproduce

  1. Create Scene.
  2. Launch game in windowed mode.
  3. Resize game window.

Minimal reproduction project (MRP)

N/A, bug appears in brand new projects.

@akien-mga
Copy link
Member

akien-mga commented Jul 8, 2024

I don't seem to reproduce the issue on:

Fedora Linux 40 (KDE Plasma) - Wayland - Vulkan (Forward+) - dedicated AMD Radeon RX 7600M XT (RADV NAVI33) - AMD Ryzen 7 7840HS w/ Radeon 780M Graphics (16 Threads)

Could you test earlier beta/dev snapshots and pinpoint the first one where the regression is apparent?

In case you upgraded your Nvidia drivers today, be sure to test again after rebooting. Nvidia drivers are usually left in a broken state after upgrade on Linux until the next reboot.

@DraconicMentalist
Copy link
Author

I haven't updated my system today, but still rebooted just in case. This issue is still present.

I decided to test this under Hyprland (Wayland) as well, and it seems that it isn't X11 related at least. I also went off and tested previous dev snapshots, and the first occurrence of this issue appears to be in Godot Dev 4.

@Giganzo
Copy link
Contributor

Giganzo commented Jul 8, 2024

Getting the same error message with:
Godot v4.3.beta2 - Fedora Linux 39 (KDE Plasma) - X11 - Vulkan (Forward+), and nvidia; 555.58.02

Edit: Don't see the error if using compatibility

@akien-mga akien-mga changed the title Project throwing "screen_prepare_for_drawing: Unable to acquire framebuffer" error when resizing game window. Project throwing "screen_prepare_for_drawing: Unable to acquire framebuffer" error when resizing game window (Nvidia, Linux) Jul 8, 2024
@akien-mga
Copy link
Member

Haven't tested as I can't reproduce, but a potential culprit for the regression in dev 4 would be #87340, which is the PR adding screen_prepare_for_drawing where the error originates.

CC @DarioSamo

@DarioSamo
Copy link
Contributor

DarioSamo commented Jul 8, 2024

I suggest gathering more information of the events leading up to the error as to avoid blindly chasing the issue since when it concerns swap chains and drivers there's way too many variables and errors that could be happening one after the other, with the real issue happening much earlier than when the error is reported. There's not a lot you can get out of reviewing the implementation here, just basically looking at what the driver is returning and if the error can be handled more gracefully.

The points of interest are RenderingDeviceDriverVulkan::swap_chain_acquire_framebuffer and RenderingDeviceDriverVulkan::swap_chain_resize.

@DarioSamo
Copy link
Contributor

In particular, can you verify if it's going through this branch of code by any chance?

} else if (err != VK_SUCCESS && err != VK_SUBOPTIMAL_KHR) {
// Swap chain failed to present but the reason is unknown.
// Refer to the comment in command_queue_present() as to why VK_SUBOPTIMAL_KHR is handled the same as VK_SUCCESS.
return FramebufferID();
}

@Ansraer
Copy link
Contributor

Ansraer commented Jul 9, 2024

We took a look at this issue in today's rendering team meeting. We suspect that nvidia somehow managed to break things in the driver.

Looking at https://www.nvidia.com/en-us/drivers/unix/ it would appear that 555.58.02 is an experimental driver version meant to be used to test new features.
We would recommend that for now you downgrade to driver version 550, which according to nvidia is stable and meant for production use.

This is still an issue that needs to be fixed, but we probably will need to talk to nvidia for this, which will take some time.

@DarioSamo
Copy link
Contributor

This is still an issue that needs to be fixed, but we probably will need to talk to nvidia for this, which will take some time.

We at least have something to go on that the issue doesn't happen before the PR, so I think it can realistically be worked around with by just looking at where exactly it's failing.

Some of the error handling around swap chains was made a bit more strict with the PR, so it probably needs to be relaxed a bit to handle whatever order of errors they're throwing around on the updated driver, even if it's a bit broken.

Do we have anyone who can help breakpoint it and gather the order of the errors and where exactly it happens?

@Calinou
Copy link
Member

Calinou commented Jul 9, 2024

I can confirm this on:

Godot v4.3.beta (82cedc8) - Fedora Linux 40 (KDE Plasma) - X11 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 4090 (nvidia; 555.58.02) - 13th Gen Intel(R) Core(TM) i9-13900K (32 Threads)

It mainly occurs when a subwindow is resized. It rarely occurs when the main window is resized, unless it's resized really fast by dragging its handles.

Project Settings and Editor Settings popups seem to suffer from this issue more easily, perhaps because of their increased Control complexity.

framebuffer.mp4

In particular, can you verify if it's going through this branch of code by any chance?

I've added a print_line() statement in there (above return) and it was never printed.

Looking at nvidia.com/en-us/drivers/unix it would appear that 555.58.02 is an experimental driver version meant to be used to test new features.

It's also the version RPMFusion in Fedora 40 ships with by default 🙂

It seems quite a lot of users are on 555 already, since it also has greatly improved Wayland support with explicit sync.

@DarioSamo
Copy link
Contributor

DarioSamo commented Jul 9, 2024

It mainly occurs when a subwindow is resized. It rarely occurs when the main window is resized, unless it's resized really fast by dragging its handles.55 already, since it also has greatly improved Wayland support with explicit sync.

Then it is very likely this code.

bool resize_required = false;
RDD::FramebufferID framebuffer = driver->swap_chain_acquire_framebuffer(main_queue, it->value, resize_required);
if (resize_required) {
// Flush everything so nothing can be using the swap chain before resizing it.
_flush_and_stall_for_all_frames();
Error err = driver->swap_chain_resize(main_queue, it->value, _get_swap_chain_desired_count());
if (err != OK) {
// Resize is allowed to fail silently because the window can be minimized.
return err;
}
framebuffer = driver->swap_chain_acquire_framebuffer(main_queue, it->value, resize_required);
}
ERR_FAIL_COND_V_MSG(framebuffer.id == 0, FAILED, "Unable to acquire framebuffer.");

One issue I've seen NVIDIA/Linux trigger on the latest driver is it'll be able to fail immediately after creating the swap chain if you're resizing the window.

I think the solution here would be to just allow it to fail silently if it fails to acquire the framebuffer again and just let it attempt it again next frame. It's basically doing its best but it'd be dangerous to constantly attempt over and over to resize the swap chain and acquire the framebuffer endlessly.

It'd be as simple as turning the error into an early return basically:

ERR_FAIL_COND_V_MSG(framebuffer.id == 0, FAILED, "Unable to acquire framebuffer.");

into

if (framebuffer.id == 0) {
   return ERR_CANT_CREATE; // Or whatever other error we deem appropriate here.
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Very Bad
Development

Successfully merging a pull request may close this issue.

6 participants