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
Conversation
This caused the triangles button in osu! to render with different dark colours.
There was a problem hiding this 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); |
There was a problem hiding this comment.
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.
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..
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
SampleGame/SampleGameGame.cs
Outdated
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
@@ -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); |
There was a problem hiding this comment.
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.
public UniformBool BackbufferDraw; | ||
private readonly UniformPadding8 pad1; | ||
private readonly UniformPadding12 pad1; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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>
osu.Framework.Tests/Visual/Drawables/TestSceneGammaCorrection.cs
Outdated
Show resolved
Hide resolved
osu.Framework.Tests/Visual/Drawables/TestSceneGammaCorrection.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Susko3 <Susko3@protonmail.com>
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:
(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:But this matches both browser, and figma as well:
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.