Comment by ~eliasnaur on ~eliasnaur/gio
On Sun Jan 17, 2021 at 10:03 AM CET, ~egonelbre wrote:
color.RGBA(1, 1, 1, 1)
isn't a white color with transparency, it's gray with transparency (assuming it's255 * (linear-non-premul * alpha)^1/2.2
variant).x := color.RGBA{1,1,1,1} fmt.Println(f32color.RGBAToNRGBA(r)) // Output: {79 79 79 1}
That's a good point I completely overlooked. ~vsariola, besides the unintuitive blending result, does color.NRGBA{79,79,79,1} (or something darker than 255) solve your issues? And if not, does switching to color.RGBA somehow fix your issues? If not, this issue is about switching to a higher precision, for example NRGBA64. We're bound to have to deal with higher precision anyway, given the fancy newer HDR formats which use more than 8 bits per color channel all the way through to the framebuffer.
Great discussion, thanks.
Comment by ~eliasnaur on ~eliasnaur/gio
On Sat Jan 16, 2021 at 7:21 PM CET, ~egonelbre wrote:
Yes, it should've been "sRGB u8 premul to linear". Typo from copy-paste. And, yes, looks like I made a mistake in the formulas and calculations, however I made two mistakes, so it cancelled out :D.
Here's trying to redo the calculations:
// The definitions: linear-premul = linear-non-premul * alpha srgb = (linear-non-premul * alpha)^1/2.2 * 255 ==> linear-non-premul = (srgb / 255)^2.2 / alpha linear-premul = (srgb / 255)^2.2 / alpha * alpha = (srgb / 255)^2.2 linear-non- premul = 1.0, alpha=1/255 srgb = (1.0 * 1/255)^1/2.2 * 255 linear- premul = (((1.0 * 1/255)^1/2.2 * 255) / 255)^2.2 = 1/255
I think we're both right, but under different assumptions. I'm assuming ~vsariola would represent the color.NRGBA(255, 255, 255, 1) overlay in pre.multiplied color.RGBA as (1, 1, 1, 1), and you seem to assume it will be represented as (c, c, c, 1), where c=(1.0*1/255)^(1/2.2)*255 =~ 21 (or =~ 13 with the EXT_sRGB formula). color.RGBA(1, 1, 1, 1) converted to linear results in (l, l, l, 1/255) where l=(1/255)^2.2 under my assumption, and l=1/255 under your assumption.
If I'm right (am I?), the problem is that there is a loss of precision with NRGBA that doesn't exist in RGBA (because the alpha is pre-multiplied before gamma adjustment). That's a serious flaw of NRGBA and I wonder what precision issues exist in RGBA that don't exist in NRGBA. If there are none/fewer/less severe I think we should consider switching back to RGBA, and suffer the performance penalty and non-intuitiveness of alpha-multiplying a color.RGBA value.
Comment by ~eliasnaur on ~eliasnaur/gio
I don't understand your second calculation. Why are you mentioning "non-premul"?
// Converting from sRGB u8 non-premul to linear ((srgb/0xff)/alpha)^2.2 * alpha Source linear premul f32 : ((1/255) / (1/255))^2.2 * 1/255, A:1/255 1/255, A:1/255
I'd say the correct calculation is
// Converting from sRGB u8 premul to linear (srgb/0xff)^2.2 Source linear premul f32 : (1/255)^2.2, A:1/255
and 1/255 is != (1/255)^2.2.
This is what https://gioui.org/commit/99bfa6a (incorrectly) implemented, and it did change OP's blending problem to output (1, 1, 1) as one would (naively) expect.
Comment by ~eliasnaur on ~eliasnaur/gio
Thanks for the detailed answer, Egon. Would color.RGBA make any difference in this case? I assume yes, and if so, do you still think the color.NRGBA colorspace is the correct choice for Gio?
Do any of you know what other GUI libraries/browsers do about loss of precision problems?
Comment by ~eliasnaur on ~eliasnaur/gio
Good points. I don't know the best solution, so I'll re-open this issue for discussion.
RESOLVED FIXED REPORTED
Comment by ~eliasnaur on ~eliasnaur/gio
Indeed. I think the API should be to add a SetOptions to Window and reuse the existing WindowOptions such as Title. See also https://github.com/gioui/gio/pull/10#issuecomment-757484484.
I don't know whether ~inkeliz is working on SetOptions; I suggest you notify him on the PR if you want to avoid duplicate work.
Comment by ~eliasnaur on ~eliasnaur/gio
I find these gammas always confusing :) So apologies if I'm not grasping all the issues. But if there's final ^1/2.2, why isn't there initial ^2.2 when going from NRGBA to pre-multiplied linear?
There is a ^2.2 applied, but only to the color values. In your NRGBA(255, 255, 255, 1) case, the gamma conversion is applied to 255 which is still 255.
Would the last system for storing color proposed in http://ssp.impulsetrain.com/gamma-premult.html solve this problem?
That's what we had with color.RGBA. We switched to NRGBA because of loss of precision issue (I'll let others supply details), and because it was non-intuitive and expensive to multiply alpha (you need to un-gamma, multiply, gamma all color components).
Anyways, I'm doing material.io style dark theme overlays, and there often the recommendation is to apply e.g. a 5% white overlay, but I find it hard to apply these translucent overlays with the new NRGBA system because even alpha = 1 white is so bright, so I don't have the granularity to apply the amount of color I'd want.
Would it help to use a less brighter white and a higher alpha?
I've notified the people more informed than myself in the Slack thread, https://gophers.slack.com/archives/CM87SNCGM/p1610723351011700, to comment here.
It's possible we'll need to change the color representation again, perhaps to a new sRGB-aware color type.
Comment by ~eliasnaur on ~eliasnaur/gio
Egon Elbre convinced me my "fix" was in fact wrong. See https://gioui.org/commit/99bfa6a. I now see this issue as an artifact of linear alpha values. From your program, using the sRGB formulas from http://ssp.impulsetrain.com/gamma-premult.html, https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_sRGB.txt, and https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBlendFunc.xhtml:
The NRGA(255, 255, 255, 1) sRGB color is converted to (1/255, 1/255, 1/255, 1/255) pre-multiplied linear color. Our blend funcs are (1, 1-srcAlpha), so blending against your NRGBA(0, 0, 0, 255) converted to (0,0, 0, 1) pre-multiplied linear color gives: (1/2551 + 0(1-1/255), ..., (1/255)1+1(1-1/255)) = (1/255,..., 1). Converting that back to sRGB is NRGBA(12.92, ..., 255), rounded to the (13, 13, 13, 255) you see as a result.
Comment by ~eliasnaur on ~eliasnaur/gio
I believe your issue is fixed by gioui.org/commit/01d5e72. Let me know if it isn't.
REPORTED RESOLVED FIXED