godotengine / godot

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

Auto Exposure cause the whole editor to become non-responsive #78876

Open bitinn opened 1 year ago

bitinn commented 1 year ago

Godot version

v4.1.rc2.official [46424488e]

System information

macOS Monterey, MBP 2020, Intel Iris Plus Graphics, Forward+

Issue description

Screen Shot 2023-06-30 at 22 44 38

Enabling Auto Exposure in Camera Attributes cause the whole editor to lag in a fresh project and fresh scene.

Screen Shot 2023-06-30 at 23 03 45 Screen Shot 2023-06-30 at 23 04 25

Also very high GPU usage is observed when auto exposure is enabled, even though the scene is mostly blank.

(Issue is also reproduced in Godot v4.0.3 stable)

Steps to reproduce

  1. Download minimal repo project
  2. Notice the physical light unit is enabled in project settings
  3. Adjust Exposure under Camera Attributes under Environment node, notice exposure is working as intended
  4. Enable Auto Exposure, notice the editor hangs and only response every a few seconds.
  5. Disable Auto Exposure and everything works normally.

Minimal reproduction project

bread-house-rc.zip

bitinn commented 1 year ago

Similar issue was reported in #13378 but was closed as a non-issue.

I am not sure I agree? I don't see auto exposure as a very expensive rendering feature.

bitinn commented 1 year ago

Did some tests with Radeon Pro (RX) 580 and it's indeed creating quite a bit of processing overhead (0.5ms~1.0ms, RX 580 has around the same processing power as GTX 1650), but not seeing the same significant slowdown like on Intel GPU.

I think the current implementation of auto exposure is particular slow on Intel GPU.

Screen Shot 2023-07-02 at 0 04 50 Screen Shot 2023-07-02 at 0 05 06

Pro 580 (with and without auto exposure)

Screen Shot 2023-07-02 at 0 09 09 Screen Shot 2023-07-02 at 0 06 58

Intel Iris (with and without auto exposure)

clayjohn commented 1 year ago

Wow, that is indeed horrible performance. Something pathological must be happening. A few things come to mind: 1) compute shaders are already pretty slow with Intel (as are any advanced effects) 2) something could be going wrong in the translation of Vulkan to Metal (macOS can't run Vulkan)

Calinou commented 1 year ago

Remember that asking an Intel IGP to render a scene at a Retina display's native resolution is asking a lot from it. Consider running Godot in low-DPI mode so that the pixel count is divided by 4 (50% scale on each axis). This should speed up rendering a lot.

You can also use the 3D Scaling project settings (set it to Bilinear and 0.5), but this won't bring as much of a speedup since only the 3D buffer is downscaled.

Also very high GPU usage is observed when auto exposure is enabled, even though the scene is mostly blank.

On top of having a fixed cost to estimate the scene's exposure, autoexposure requires continuous editor redrawing, so this is expected.

I am not sure I agree? I don't see auto exposure as a very expensive rendering feature.

Autoexposure isn't very expensive in itself, but running it on integrated graphics and at a high resolution is bound to make it an expensive feature.

bitinn commented 1 year ago

Remember that asking an Intel IGP to render a scene at a Retina display's native resolution is asking a lot from it. Consider running Godot in low-DPI mode so that the pixel count is divided by 4 (50% scale on each axis). This should speed up rendering a lot.

While I agree this is good advise in general, I have tried a 1/16 resolution and the performance is still abysmal with auto exposure compared to without it.

Screen Shot 2023-07-02 at 2 07 42 Screen Shot 2023-07-02 at 2 08 41

Even with low DPI + 1/16 res this is still much slower than expected. But at least we know this has something to do with amount of pixels to render.

Screen Shot 2023-07-02 at 2 17 11
FishOfTheNorthStar commented 5 months ago

"autoexposure requires continuous editor redrawing"

It took me a while to figure out why the editor was continously updating, it was auto exposure. I kind of understand why it's necessary, but I was wondering if there's some way to throttle this behavior, or limit it? I'd like to have auto exposure on and still have the editor shut down updates eventually, like maybe if exposure levels have stabilized.

Calinou commented 5 months ago

I'd like to have auto exposure on and still have the editor shut down updates eventually, like maybe if exposure levels have stabilized.

We could likely do something similar to what's proposed in https://github.com/godotengine/godot/issues/54893, and assume that autoexposure has fully converged after a certain amount of time has passed (depending on the autoexposure speed property). At the default speed, this would probably be around 5 to 8 seconds.

Note that unlike TAA or volumetric fog convergence, autoexposure converge is based in real time, not frames rendered.

FishOfTheNorthStar commented 5 months ago

That sounds like a good plan. A few things came to mind, a bit on the subject.

I just noticed that having any kind of fog volume visible in a scene causes continuous updates as well, which seems odd to me but maybe the froxel fading functions are similar to the auto exposure in they need a while to level off. So maybe fog volumes updates could similarly be throttled as you described.

Another thing I noticed regarding continuous updates and the TIME variable in shaders: The docs state that having a uniform that does not change, and using it in an 'if' block (not a preprocessor if, just a regular glsl if) gets optimized into being functionally identical to as if you had done the same but with preprocessor if's. I found a little discrepancy with that and maybe resolving it could help with this update situation (but not how it interacts with auto-exposure, this is more about how TIME access effectively causes the same result).

What I found is if I add a uniform bool to the effect of 'enable_time", and then I create a function like 'get_current_time' that, if enable_time is true, returns TIME or if false, returns 0., that did not suppress the updates. But if i did same but with preprocessor if's, it did. But such a uniform bool could be very useful for developers, if it worked as intended, so perhaps where the 'detect if TIME is in use in current shaders' function looks for that access, it could happen later, after the preprocessor / optimizer has already pruned dead branches, which seems like it would arrive at the desired result then, and might not be too big of a change to implement.

(full disclosure, I'm in 4.2.2 stable so maybe this has already been resolved)

Related: a hidden mesh using a shader that access's TIME still triggers updates even if it is hidden. I could file a bug on that if that's appropriate, but maybe it has to be that way, I don't know.

Calinou commented 5 months ago

ps: it's OT but I'm trying to hack the TAA buffer with blue noise dithering for a cross fade effect between any three planes of a triplanar shader but implemented with one sample instead of three. You mention TAA so i'm just wondering if anyone could direct me towards resources where I could look into how feasible this is with Godot? Thanks.

Jittering the samples with a noise that varies with TIME should do the trick. There's no need to hack the TAA buffer at a low level to do this. See https://github.com/godotengine/godot/pull/61834.