godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Add a project setting to continue drawing while the window is minimized #1931

Open abb128 opened 3 years ago

abb128 commented 3 years ago

Describe the project you are working on

An OpenVR dashboard overlay

Describe the problem or limitation you are having in your project

I am currently passing the texture of a Viewport to SteamVR through a GDNative module in order to create a dashboard. This dashboard is accessible within SteamVR and it can be viewed even if the window is minimized on the desktop, or even if there's no window at all.

In Windows Mixed Reality, entering VR mode can minimize all of your desktop windows depending on your settings, in order to improve performance for VR.

Godot Engine currently stops rendering if the window is minimized on desktop, presumably to avoid unnecessarily rendering:

bool OS_Windows::can_draw() const {

    return !minimized;
};

( https://github.com/godotengine/godot/blob/3.2.3-stable/platform/windows/os_windows.cpp#L272 )

All of these factors combined make it so that my dashboard is useless and does not re-render unless the user manually makes sure to open the window on their desktop, so that the engine can continue rendering.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

The ability to override can_draw(), or even just an option to allow rendering while minimized, would allow the dashboard to continue rendering regardless of the state of the actual window.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

I'm unsure about how to actually design overriding that method (ideas would be appreciated), but one simpler solution would be to simply have a boolean project setting called display/window/energy_saving/render_while_minimized.

If this enhancement will not be used often, can it be worked around with a few lines of script?

This is not scriptable functionality as it is part of the engine. For now, I had to build a custom version of the engine with the can_draw method above replaced with

bool OS_Windows::can_draw() const {

    return true;
};

Is there a reason why this should be core and not an add-on in the asset library?

See above

Calinou commented 3 years ago

Another use case for this is performing offline rendering while the window is minimized.

vilhalmer commented 2 months ago

Now that tray icons are on the way (godotengine/godot#80211) this would be even more useful, since for VR overlays we could hide the window away entirely.

vilhalmer commented 1 month ago

This is now possible using DisplayServer::register_additional_output: https://github.com/godotengine/godot/pull/94412

pochoco24 commented 1 month ago

@Calinou I am using Game Capture, but there aren't any options for capturing minimized windows.

Some Unity programs like VSeeFace keep rendering while minimized with Game Capture without any extra set up in OBS.

pochoco24 commented 1 month ago

In vulkan_context.cpp:

if (window->width == 0 || window->height == 0) {
    free(presentModes);
    // Likely window minimized, no swapchain created.
    return ERR_SKIP;
}

I've tried to change it so it creates a swapchain for rendering in minimized windows, but now it doesn't let me un-minimize the window back:

if (window->width == 0 || window->height == 0) {
    swapchainExtent.width = 1152;
    swapchainExtent.height = 648;
    window->width = 1152;
    window->height = 648;
}
pochoco24 commented 1 month ago

@Calinou Apart from can_any_window_draw(), there's another function in display_server_windows.cpp:

bool DisplayServerWindows::window_can_draw(WindowID p_window) const {
    _THREAD_SAFE_METHOD_

    ERR_FAIL_COND_V(!windows.has(p_window), false);
    const WindowData &wd = windows[p_window];
    return !wd.minimized;
}

After changing it to return true always, the window still doesn't update when minimized.

Calinou commented 1 month ago

I wonder if this is something that requires https://github.com/godotengine/godot-proposals/issues/5692 to work with Vulkan.

pochoco24 commented 1 month ago

@Calinou How so?

Calinou commented 1 month ago

@Calinou How so?

I don't know, I'm just guessing here 🙂

pochoco24 commented 1 month ago

@dsnopek What are your thoughts on what could be causing this? (Mentioning since you added the minimized rendering feature)

dsnopek commented 1 month ago

@pochoco24 I don't know. The feature I worked on was specifically to fix a VR-related issue, which is fixed by the work I did. Like I said in previous comment (which I can't seem to find right now - this conversation is spread across a few places), I suspect there's something special that needs to be done for Windows or OBS, but I don't personally know what. Someone will need to do the research and some experimentation!

pochoco24 commented 1 month ago

@Calinou @dsnopek From the OBS Documentation, OBS directly captures the DirectX or OpenGL of the game, and it also supports Vulkan.

Do you know what files handle Vulkan (Forward+) or OpenGL 3 (Compatibility) so I can check them out?

Calinou commented 1 month ago

The Vulkan context is created in drivers/vulkan/rendering_context_driver_vulkan.cpp, with some Windows-specific code in platform/windows/rendering_context_driver_vulkan_windows.cpp.

The OpenGL context is created in platform/windows/gl_manager_windows_native.cpp on Windows.

pochoco24 commented 1 month ago

@Calinou In gl_manager_windows_native.cpp, there's a function that gets called every frame, even if the window is minimized:

void GLManagerNative_Windows::swap_buffers() {
    SwapBuffers(_current_window->hDC);
}

I want to check if SwapBuffers() has something that prevents minimized rendering, but VSCode can't find any references to SwapBuffers in any file 🤔

Calinou commented 1 month ago

SwapBuffers() is a Windows API function: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-swapbuffers

pochoco24 commented 1 month ago

@Calinou I managed to get it working (kind of) with a bare-bones Vulkan renderer. I just removed the handling minimization snippet and ensured that the swapchain renders at window resolution.

https://github.com/user-attachments/assets/194d0f43-7899-4522-b5e0-9b16a634cd7f

Since VSeeFace can do minimized rendering and uses DX11 with a DXGI swapchain, someone ran the demo by layering a DXGI swapchain with driver settings:

image

and they said it works just fine, but it still complains about being out-of-date. Using an actual DXGI swapchain in Godot would be the way to go, so your initial guess was right! #5692

pochoco24 commented 2 weeks ago

@Calinou ITS FIXED NOW!! It works specifically for Windows using Direct3D 12 on the new Godot 4.3 build

In the source code, go to file rendering_device_driver_d3d12.cpp and change the line 2506 from: res = swap_chain->d3d_swap_chain->ResizeBuffers(p_desired_framebuffer_count, 0, 0, DXGI_FORMAT_UNKNOWN, creation_flags); to: res = swap_chain->d3d_swap_chain->ResizeBuffers(p_desired_framebuffer_count, surface->width, surface->height, DXGI_FORMAT_UNKNOWN, creation_flags);

In Godot Project Settings set the Renderer Device to d3d12 (for windows), then, make a script that registers an additional output so it keeps rendering even when there are no visible windows available:

extends Node

var object = Object.new()

func _ready() -> void:
    DisplayServer.register_additional_output(object)

# Free the object before closing the game
func _notification(what: int) -> void:
    if what == NOTIFICATION_WM_CLOSE_REQUEST:
        object.free()

Now when minimizing the window, it keeps rendering.

MudkipWorld commented 5 days ago

@Calinou ITS FIXED NOW!! It works specifically for Windows using Direct3D 12 on the new Godot 4.3 build

Hi, since a fix got found. Would it be possible to have this feature as a project settings toggle maybe? I personally need it too since I am working on a Vtubing software which needs stuff top stay rendering when the window is minimized. I think the feature could be useful for making other non-game based projects 👀

If this feature happen to get added, would you mind informing me?