wgpu icon indicating copy to clipboard operation
wgpu copied to clipboard

Vulkan color space is different when rendering to swap chain (sRGB)

Open valaphee opened this issue 7 months ago • 12 comments

Description When comparing the cube and water example for different back-ends on window (screenshots even of Vulkan seems to be fine which is weird). The colors are noticeable different.

The colors on Vulkan are darker compared to the screenshots and GL, DX12.

Repro steps Run the cube or water example with WGPU_BACKEND=dx12 and with WGPU_BACKEND=vulkan

Expected vs observed behavior Darker colors compared to the baseline and other back-ends window output.

Extra materials DX12/OpenGL (AMD RX 6900 XT, Win 10/11, No HDR), Vulkan/OpenGL (AMD RX 6900 XT, Linux, No HDR) (expected?): Screenshot 2023-12-14 163957 Vulkan (AMD RX 6900 XT, Win 11, No HDR): Screenshot 2023-12-14 164014 Vulkan (Nvidia RTX 3070, Win 10, No HDR): Unbenannt

wgpu-info.json

Platform

valaphee avatar Dec 06 '23 23:12 valaphee

Might be related to https://github.com/gfx-rs/wgpu/issues/1646 and https://github.com/gfx-rs/wgpu/issues/3449, but probably not. As the format seems correct and it also looks right in RenderDoc, but Vulkan seems to do some gamma correction on its own.

valaphee avatar Dec 07 '23 13:12 valaphee

@cwfitzgerald any ideas why this is happening?

teoxoy avatar Dec 11 '23 10:12 teoxoy

This looks like a tale of different primaries. When outputting SDR, what the output of compositing isn't sRGB. It's your monitor's color space.

What looks like it's happening is that DX12 is outputting sRGB color (by converting the sRGB into the monitor's color space), whereas vulkan is just yeeting the colors into the monitor and hoping for the best.

In short, I'm not sure there's much we can do about this.

cwfitzgerald avatar Dec 12 '23 18:12 cwfitzgerald

Updated the images, I guess the color channel issue is not related to the linear/non-linear color space issue, but interestingly at least the color space is correct on Nvidia. (But I guess its most likely really a vendor issue)

On Linux Vulkan works perfectly fine.

What's the reason why DX12 is not the default on Windows?

valaphee avatar Dec 14 '23 23:12 valaphee

What looks like it's happening is that DX12 is outputting sRGB color (by converting the sRGB into the monitor's color space), whereas vulkan is just yeeting the colors into the monitor and hoping for the best.

Theoretically both Vulkan and Dx12 should set/communicate to DWM what the color space of the output swapchain is, and DWM will appropriately convert it:

https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range

Then it's up to the SDR->HDR settings in Windows to map the brightness, which is expected to behave the same.

(In our renderer, which does not utilize WGPU, and we disable automatic sRGB conversion by using _UNORM textures, the color output in Vulkan and Dx12 is the same, on a 6800 XT)

Maybe useful to make sure that:

MarijnS95 avatar Dec 15 '23 14:12 MarijnS95

On Linux Vulkan works perfectly fine.

What compositor do you use on Linux that has HDR support?

MarijnS95 avatar Dec 15 '23 15:12 MarijnS95

X11, and Wayland, on two different machines, one with an AMD iGPU and the other one had a Nvidia dGPU and an Intel iGPU, and both worked fine with both compositors, no HDR enabled (nor supported).

The surface descriptor is also quite similar for both platforms.

valaphee avatar Jan 01 '24 14:01 valaphee

Windows 11 (23H2) AMD 6800xt (23.11.2 drivers) no hdr I get identical colours with both vulkan and dx12. (also the background colour on the cube example is blue for me by default, not green?)

Elabajaba avatar Jan 12 '24 23:01 Elabajaba

Forget to mention, the default is majority blue, but I changed it to pure green to compare the color values of the screenshots.

Tested with latest commit, but that's odd, I'm using the latest 23.12.1 drivers, HDR is disabled, also tried different display options. (color depth 8/10 bpc, limited/full rgb)

Would be interesting if someone with an RX 6900XT could test.

valaphee avatar Jan 15 '24 09:01 valaphee

Did some further testing, because I was wondering why wgpu doesn't use HDR by default, and found that the first supported format is used by default.

And when using Rgba16Float with Vulkan the image looks like the expected one, same with DX12, but with OpenGL the color space is wrong.

valaphee avatar Jan 17 '24 10:01 valaphee

~Updated the issue because on Linux there is a similar problem involving OpenGL (non-es) where the ES variant results in the same image as Vulkan, but OpenGL (non-es) looks the same as Vulkan on Windows 11~

valaphee avatar Apr 03 '24 15:04 valaphee

pub fn map_vk_surface_formats(sf: vk::SurfaceFormatKHR) -> Option<wgt::TextureFormat> {
    use ash::vk::Format as F;
    use wgt::TextureFormat as Tf;
    // List we care about pulled from https://vulkan.gpuinfo.org/listsurfaceformats.php
    Some(match sf.color_space {
        vk::ColorSpaceKHR::SRGB_NONLINEAR => match sf.format {
            F::B8G8R8A8_UNORM => Tf::Bgra8Unorm,
            F::B8G8R8A8_SRGB => Tf::Bgra8UnormSrgb,
            F::R8G8B8A8_SNORM => Tf::Rgba8Snorm,
            F::R8G8B8A8_UNORM => Tf::Rgba8Unorm,
            F::R8G8B8A8_SRGB => Tf::Rgba8UnormSrgb,
            _ => return None,
        },
        vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT => match sf.format {
            F::R16G16B16A16_SFLOAT => Tf::Rgba16Float,
            F::R16G16B16A16_SNORM => Tf::Rgba16Snorm,
            F::R16G16B16A16_UNORM => Tf::Rgba16Unorm,
            F::A2B10G10R10_UNORM_PACK32 => Tf::Rgb10a2Unorm,
            _ => return None,
        },
        _ => return None,
    })
}

this is also not ideal, as A2B10G10R10_UNORM_PACK32 can be both, nonlinear and linear, and I guess this is also true for all other formats.

But this check is hardcoded

let color_space = if config.format == wgt::TextureFormat::Rgba16Float {
            // Enable wide color gamut mode
            // Vulkan swapchain for Android only supports DISPLAY_P3_NONLINEAR_EXT and EXTENDED_SRGB_LINEAR_EXT
            vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT
        } else {
            vk::ColorSpaceKHR::SRGB_NONLINEAR
        };

and doesn't match up with above

valaphee avatar Apr 24 '24 19:04 valaphee