hasenbanck / egui_wgpu_backend

Backend code to use egui with wgpu.
Apache License 2.0
90 stars 75 forks source link

Support wasm by disabling `linear_from_srgb` in the shader on non-srgb display formats. #16

Closed expenses closed 3 years ago

expenses commented 3 years ago

I would like to be able to run this on the web, however as mentioned in https://github.com/hasenbanck/egui_wgpu_backend/issues/9, the web display format is non-srgb, e.g. Bgra8Unorm. We're currently converting from linear colour to srgb colour in the vertex shader which looks wrong on wasm but if we change this line: https://github.com/hasenbanck/egui_wgpu_backend/blob/9d03ad345d15d1e44165849b242d3562fdf3e859/src/shader/egui.vert#L26 to

v_color = color / 255.0; 

Then the output looks perfect on wasm!

1615839565

The best way to go about this is probably to have 2 shaders, and switch between them either on output_format or a feature flag.

hasenbanck commented 3 years ago

Actually, the web format "Bgra8Unorm" is highly misleading. It's not the final output format for the canvas (I should remove that check for the format).

Shaders normaly operate in linear space, so that you can properly calculate your lightning. The API normaly takes care of converting textures that are encoded in sRGB gamma to linear space and also makes sure to later convert the back buffer into the correct output format for your system (currently mainly sRGB based). We in the shader make sure that the color values we upload are in linear space, since native APIs expect this behavior.

The web is weird. The WGL and to an extend WebGPU don't specifiy the color spaces / gamma encodings .... And most browsers actually expect you to output sRGB from your shaders (so if you would like to have properly looking shaders / lighning you would need to do sRGB -> linear -> shader operations -> SRGB).

To quote:

The color space of content displayed in an HTMLCanvasElement via 2D Canvas, WebGL, or WebGPU, is not explicitly defined. The de facto behavior of most browers is to limit this content to the sRGB color space, with 8 bits per color. This presents a significant limitation compared to the capabilities of display devices and the demands of content creators.

https://github.com/WICG/canvas-color-space/blob/main/CanvasColorSpaceProposal.md

Since we don't do any shading / lighning here, we could indeed just upload the sRGB encoded data, without converting it into linear space.

It should most likely a second fragent shader that is gated behing a compile flag ("target = web...").

hasenbanck commented 3 years ago

Please have a look at the current HEAD were I tried to fix the issue.

expenses commented 3 years ago

Awesome! Great write-up and the changes you've made solve this problem well. The one thing I'd suggest is that instead of doing #[cfg(target_arch = "wasm32")], you add a feature flag and use #[cfg(feature = "web")], as a native wasm32 target could use wgpu with a srgb render attachment.

hasenbanck commented 3 years ago

Added the suggested changes to HEAD.

expenses commented 3 years ago

Perfect! Think we can close this now.