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

Buffering 2d hdr subviewport leaves image slightly darker (problem for cumulative effects) #100517

Open
RichMakeGame opened this issue Dec 17, 2024 · 5 comments

Comments

@RichMakeGame
Copy link

Tested versions

reproducible in 4.3 stable

System information

Godot v4.3.stable - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1650 (NVIDIA; 32.0.15.6614) - Intel(R) Core(TM) i3-10100 CPU @ 3.60GHz (8 Threads)

Issue description

I'm making a 2d paint app (see image at the end) in Godot and it relies on taking a buffered image (using a subviewport and rendering a copy), making a change to it and sending back to the buffer, over and over as the user paints. This works perfectly using srgb, the buffered image is a perfect duplicate and can be altered continuously with no loss of fidelity.

However, I'd like to use 2d hdr mode for the subviewports so I can do colour mixing in linear space and make use of the higher bit depth. But doing this results in image degradation as the image gets very slightly darker with each buffer eventually becoming black, making it impossible to use.

here's some screenshots from the example project, which repeatedly bounces a coloured image between two subviewports:
frame 1: no noticeable change yet:
Image

frame 400: buffered image has become significantly darker in linear mode
Image

I don't think this is the same issue as some have brought up with having darkened views in 2d hdr, since over one frame it's very subtle. But I think that using a subviewport to buffer another should result in an exact duplicate of the image (a colorrect is displaying the image, with a shader that simply reads and displays the viewporttexture), - and it does work like this in srgb mode.

Thanks for reading

image from paint app:
Image

Steps to reproduce

open the example project and press space. a solid colour will be sent to the buffer viewport and back 400 times, on the left is srgb and right is linear, with a reference colour below. observe the linear viewport result becoming darker while srgb stays true.

Minimal reproduction project (MRP)

linear_buffer.zip

@github-project-automation github-project-automation bot moved this to For team assessment in Rendering Issue Triage Dec 17, 2024
@fire fire changed the title buffering 2d hdr subviewport leaves image slightly darker (problem for cumulative effects) Buffering 2d hdr subviewport leaves image slightly darker (problem for cumulative effects) Dec 17, 2024
@matheusmdx
Copy link
Contributor

Seems to a be a regression between 4.3 beta 3 and 4.3 rc 1, bisecting rn

@matheusmdx
Copy link
Contributor

Bisected to #93802, @feiyue-z

Image

@RichMakeGame
Copy link
Author

hello and thanks for taking a look! - while I think there is a separate issue of a missing linear>srgb conversion when I display the linear viewports texture in an srgb viewport (in my test case I had to add a conversion to get the green to match in frame 1) I don't think it's the same as the issue I'm describing.

In my case I'm bouncing viewport textures back and forth between two linear viewports, so no conversion should take place- and the amount it becomes darker each time seems much subtler than a missing conversion. it happens over a few hundred frames

finally, I tried an example using white; white should be identical between srgb and linear I think? so a missing conversion should make no difference
here's frame 1:
Image
and frame 400:
Image

what I was imagining was maybe even though both viewports are linear, maybe the texture was being converted to srgb then back to linear with an imprecise algorithm? complete stab in the dark, I don't have the expertise :)

@matheusmdx
Copy link
Contributor

matheusmdx commented Dec 20, 2024

Unfortunately I don't have any rendering related knowledge to explain for you how and why this is happening, the only thing i can guarantee for you is reverting the cited pr solves the issue. When someone from the rendering team take a look on this probably they'll be able to give you a proper answer:

unknown_2024.12.19-22.59.mp4

@clayjohn
Copy link
Member

clayjohn commented Dec 20, 2024

I tested this locally and was able to reproduce the issue.

The issue that the bisect points to should be totally unrelated in theory unless our srgb_to_linear() function is somehow converting white to something slightly less than white.

I checked in a debugger and indeed srgb_to_linear() is not returning pure white when pure white is input

Image

Further testing shows this is a floating point precision issue, using doubles makes the error go away.

Here is the calculation currently:

g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow((g + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f)

Changing it to the following is enough to fix the error:

g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow(float((g + 0.055) * (1.0 / (1.0 + 0.055))), 2.4f),

Alternatively, the following also works:

g == 1.0f ? 1.0 : g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow((g + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),

@clayjohn clayjohn moved this from For team assessment to Up for grabs in Rendering Issue Triage Dec 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Up for grabs
Development

No branches or pull requests

4 participants