godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.88k stars 20.15k forks source link

high CPU% when changing screens/monitors #76904

Open PandaTeemo opened 1 year ago

PandaTeemo commented 1 year ago

Godot version

4.0.2 release

System information

OS: Win10 CPU:I7-7700K 4.2GHz GPU1: 3080TI GPU2: Intel HD 630

Issue description

Switching main window from one monitor to another and back (different GPUs) causes permanently much higher CPU%

Steps to reproduce

using get_window().current_screen = # change from

  1. monitor 0 (3080TI) to
  2. monitor 1 (intel hd) and back to
  3. monitor 0 (3080TI)

profiling (in visual studio) showed a significant % increase in VulkanContext::swap_buffers() from step 1 to 3

variations of window settings (full/windowed/transparency/vsync) didnt seem to make (much) difference.

Minimal reproduction project

PRISM.zip

a simple spinning pyramid that follows your cursor problem primarily demo'ed by

    await get_tree().create_timer(3.0).timeout
    get_window().current_screen = 1;
    await get_tree().create_timer(3.0).timeout
    get_window().current_screen = 0;
adamscott commented 1 year ago

There's multiple factors that may in play here:

Calinou commented 1 year ago
PandaTeemo commented 1 year ago

There's multiple factors that may in play here:

  • The OS (in your case, Windows)

    • Does this have an impact on the CPU?

sorry, its actually GPU. it was grouped for some reason in my previous observation. i used the taskmanager performance tab to observe this time.

  • The GPU swap

    • How much it affects the issue?

    • Can you try to do this with two screens handled by one card?

i can only have the setup i described. new monitor (HDMI) only that can connect only to the 3080ti and ancient monitor (DVI) that can only connect to the onboard intel GPU

  • Is this at all an issue?

    • Maybe it's normal for the CPU to be in high demand as this is the CPU that needs to do the transfer?

sorry, i forgot to mention it stays high (GPU% rather). its not just during the transitions.

i did further testing and captured this chart: image with following steps:

  1. idle
  2. demo running normal as expected on 3080
  3. moving to the slower GPU (intel), util goes up for that GPU (but also the 3080!). i only observe 1 device ever allocated in vulkan (the 3080)... but my vulkan experience isnt the best so maybe this is normal
  4. moving back to the fast GPU (3080) util goes even higher for both GPUs!

but i found a workaround :D if i minimize/reopen the demo. everything goes back to normal. not very clean. but its something ;)

appended code equivalent works as well

    await get_tree().create_timer(0.1).timeout
    get_window().mode = Window.MODE_MINIMIZED
    await get_tree().create_timer(0.1).timeout
    get_window().mode = Window.MODE_WINDOWED

the delays may not be necessary and theres probably a better alternative to min/restore which ill tinker with next.

also everything works fine if manually dragging the window to the other monitor and back.

Calinou commented 1 year ago

Windows task manager's GPU usage readout is wildly known to be inaccurate. Try using an external tool such as Libre Hardware Monitor instead. At the same time, I would also look at power consumption figures, which is the best figure to know whether the GPU is actually overworked or not.

i can only have the setup i described. new monitor (HDMI) only that can connect only to the 3080ti and ancient monitor (DVI) that can only connect to the onboard intel GPU

Sounds like a job for an DVI-to-DisplayPort adapter you can connect to your 3080 Ti, as every 3080 Ti has at least 1 DisplayPort and 1 HDMI port :slightly_smiling_face:

PandaTeemo commented 1 year ago

eh. i only ever pull this 2nd monitor+intel gpu out for dev testing. and im not a multimonitor person otherwise ;) (prefer 1 huge screen... 42" currently)

similar results for power using libre image the bumped up red line at the bottom is the intel while im on the 1st monitor again. after that i minimize/restore and its normal again :) also i can just tell in the demo by the framerate loss.

  • Can you reproduce this after switching to the Compatibility rendering method in the top-right corner of the editor?

same results

  • Can you reproduce this with other apps that use OpenGL or Vulkan?

i cant think of any vulkan games/apps to reproduce with that let me explicitly switch monitors. note that by manually moving the window everything works fine.

btw this project is for an app called yolomouse which lets you change game cursors @ https://store.steampowered.com/app/1283970/YoloMouse/ im switching to godot for the overlay part of it :)

PandaTeemo commented 1 year ago

so based on previous discovery, my current in-engine solution is

ShowWindow( hwnd, SW_MINIMIZE );
ShowWindow( hwnd, SW_RESTORE );

right after a call to MoveWindow or SetWindowPos in particular when it would change monitors and gpu. i also tried a second call to SetWindowPos where it moves the screen by a pixel without overlapping the other monitor and this worked too (perhaps better than min/restore).

anyway tested and works fine and all in the same frame :)

its not a clean solution so i wouldnt consider it production worthy... but hopefully something to help investigate a better fix :)

Calinou commented 1 year ago

cc @bruvzg