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

Move gamma correction logic from renderer/shader to vertex input #5721

Merged
merged 16 commits into from Mar 31, 2023

Conversation

frenzibyte
Copy link
Member

We've generally been passing colours to the shaders in linear space, and convert the colours within the shader into sRGB space.

In Veldrid, this broke colour blending on buffered containers, as can be seen here:
image
(on the right is a box split into 50% and 100% opacity of the colour #FF6633, and on the left is the same but wrapped in a buffered container)

This breakage is essentially happening due to rendering happening in two stages and both the GPU driver and shader are incorrectly converting colour between sRGB and linear space until it ended up rendering the buffered container with a broken blend.

Rather than going through this fiasco, I've stopped both the renderer and the shader from ever applying any colour conversion in the shader, and I've instead let the framework pass colours to the shader in sRGB format.

The only difference this PR resulted in is ColourInfo.Gradient{Horizontal,Vertical} interpolating in sRGB space (gamma-incorrect), making it stand different from the other samples in the test scene:

image

But this matches both browser, and figma as well:

CleanShot 2023-03-30 at 03 20 23

So we're pretty much golden. I've updated the test scene to point as such. We can also consider replacing Interpolation.ValueAt(Colour4) with two different versions specifying in which space colours are being blended in, but I'll leave that for a follow-up PR since this one is quite stuffed.

Copy link
Sponsor Member

@peppy peppy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial pass looks pretty sane.

@@ -59,8 +72,8 @@ public struct SRGBColour : IEquatable<SRGBColour>
first.Linear.A + second.Linear.A),
};

public readonly Vector4 ToVector() => new Vector4(Linear.R, Linear.G, Linear.B, Linear.A);
public static SRGBColour FromVector(Vector4 v) => new SRGBColour { Linear = new Color4(v.X, v.Y, v.Z, v.W) };
public readonly Vector4 ToVector() => new Vector4(SRGB.R, SRGB.G, SRGB.B, SRGB.A);
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code quality failures here are likely worth considering. At very least we'd want to reduce the copy count to one by moving the property access to a local field, or at best avoid it being a computed property in the first place.

Suggested change
public readonly Vector4 ToVector() => new Vector4(SRGB.R, SRGB.G, SRGB.B, SRGB.A);
public readonly Vector4 ToVector()
{
var linear = Linear;
return new Vector4(linear.R, linear.G, linear.B, linear.A);
}

Although I don't see this inspection locally so I'm not sure where it's coming from..

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears to come from .NET's own code style analysis. I've flipped SRGBColour storage since we're using SRGB much more than we use Linear now.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we're using SRGB much more than we use Linear now.

I'm not necessarily opposed to inverting, but this conclusion is completely non-obvious to me. ApplyChild() uses multiplication ops which now end up calling ToLinear(). That will be done by every drawable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's more of which is prominent in the codebase now (in terms of direct usages). I didn't notice the operators were widely used though.

Copy link
Collaborator

@bdach bdach Mar 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said on second thought draw nodes are subject to state caching/invalidation, so the ApplyChild() calls should be 99% one-and-done init logic. So optimising for reads and avoiding .ToLinear() calls on the cpu (which inverting achieves) is probably what we want.

Also makes the struct less weird.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm slightly weirded out that the display of SampleGame is being changed just for this pull. I'd have put the boxes in a test scene instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh, this was definitely not intended.

osu.Framework/Graphics/Colour/SRGBColour.cs Outdated Show resolved Hide resolved
@@ -59,8 +72,8 @@ public struct SRGBColour : IEquatable<SRGBColour>
first.Linear.A + second.Linear.A),
};

public readonly Vector4 ToVector() => new Vector4(Linear.R, Linear.G, Linear.B, Linear.A);
public static SRGBColour FromVector(Vector4 v) => new SRGBColour { Linear = new Color4(v.X, v.Y, v.Z, v.W) };
public readonly Vector4 ToVector() => new Vector4(SRGB.R, SRGB.G, SRGB.B, SRGB.A);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we're using SRGB much more than we use Linear now.

I'm not necessarily opposed to inverting, but this conclusion is completely non-obvious to me. ApplyChild() uses multiplication ops which now end up calling ToLinear(). That will be done by every drawable.

Comment on lines 13 to 14
public UniformBool BackbufferDraw;
private readonly UniformPadding8 pad1;
private readonly UniformPadding12 pad1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have padding here and padding at the end of the global uniform block that comes out to 16 bytes total. Could/should we rearrange members here to consolidate the padding like the other pull did?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, sounds good.

Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
@bdach
Copy link
Collaborator

bdach commented Mar 30, 2023

Testing reference:

ground truth (legacy opengl on master @ windows) this PR (dx11 @ windows) this PR (legacy opengl @ android)
BorderColour (masking, colour fill, border fill) BorderColour_before BorderColour_after BorderColour_after_android
BorderSmoothing BorderSmoothing_before BorderSmoothing_after BorderSmoothing_after_android
ColourGradient ColourGradient_before ColourGradient_after ColourGradient_after_android
Effects (blur, shadow) Effects_before Effects_after Effects_after_android
The boxes GammaCorrection_before GammaCorrection_after GammaCorrection_after_android
HSVColourPicker HSVColourPicker_before HSVColourPicker_after HSVColourPicker_after_android
Video Video_before Video_after Video_after_android
WrapModes (texture sampling) WrapModes_before WrapModes_after WrapModes_after_android

TL;DR: We were mixing and matching blending before. It appears that buffered containers did gamma-incorrect blending, while Colour/BorderColour/border effects/blur shader did gamma-correct. So the last ones will change in this pull, but they will change to gamma-incorrect, which is what we want anyway to match browsers and figma designs.

Co-authored-by: Susko3 <Susko3@protonmail.com>
@bdach bdach added the next-release Pull requests which are almost there label Mar 30, 2023
@smoogipoo smoogipoo merged commit 22d7443 into ppy:master Mar 31, 2023
12 checks passed
@frenzibyte frenzibyte deleted the fix-srgb-conversion branch March 31, 2023 15:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:graphics next-release Pull requests which are almost there size/XL
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

SetPanelBackground's gradient appears lighter on veldrid renderer
5 participants