Sign in to follow this  

Vulkan When is sRGB conversion being done in Vulkan?

This topic is 406 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm in the process of moving my old Direct3D11 graphics code to Vulkan, and figured that I might as well get gamma correct from the beginning, but it's not quite right.

 

The problem is that the resulting image is too bright. What's being done as of now is simply to render objects with an albedo map to a G-buffer and then blitting that to the swapchain. There are many things that can influence the final result, and considering that the final result contradicts my intuition, there ought to be something I don't understand and I hope somebody can verify what is right and explain what is wrong.

 

Previously (which actually looked fine) I was using the first fit for swapchain format and color space when creating the swapchain, which in my case meant a UNORM format. In lack of other options, Vulkan seems to force color space to be sRGB, and since the specification indicates that the color space defines how the presentation engine interprets the data, I figured I might as well just use an sRGB format to be correct because I don't do any manual conversions.

 

This change made my image too bright, so my thought was that maybe the textures were loaded wrong the whole time. For DDS textures, the library provides the format, for which I use the Vulkan equivalent. For PNG textures I have to specify the format myself which is RGBA8_UNORM. I was surprised that the textures were not sRGB, but I double checked opening the images in VS and RenderDoc.

 

My G-buffer is RGBA8_UNORM.

 

All in all, I render linear textures to a linear G-buffer followed by blitting to an sRGB swapchain with sRGB color space. If I understand correctly, hardware should do sRGB conversions when needed, most notably when blitting the G-buffer. To me, this seems like it should work. Funny thing is that changing G-buffer to sRGB produces the same result.

 

What about shaders? If I sample an sRGB texture (which I don't right now), will the data be linear in the shader? If I write from the fragment shader, will there be any conversion depending on the render target format or does it just write the data as is, assuming that I have correctly converted it myself?

Share this post


Link to post
Share on other sites

Data sampled from an sRGB image view is always converted to linear when read by a shader. Similarly, writing to an sRGB image view will convert the linear values written by the shader to sRGB automatically. Blending is also performed in linear space for sRGB render targets.

 

Compared to OpenGL, Vulkan's sRGB features are much simpler. sRGB is simply an encoding for color data. It's simply an encoding with more precision around 0.0 and less around 1.0. That's all you really need to know when you use it. It's similar to how 16-bit floats, 10-bit floats, RGB9E5, etc work. You don't have to care about the actual encoding, just write and read linear colors. The intermediate encoding just affects the precision.

Edited by theagentd

Share this post


Link to post
Share on other sites

I would be surprised if sRGB is different in Vulkan vs OpenGL vs Direct3D. Like the previous post mentioned its just an encoding. Chances are the result you are seeing is correct, but because you've been use to the incorrect behavior all along, the correct behavior is now an anomaly. With that said, with sRGB, there are 2 things to be consider, 1. The shader inputs ( textures ) and the the target of the shader output ( render target, swap chains etc ). So just changing your textures is just a part of the puzzle. sRGB texture samples are converted to linear when read in shader. When you write fragment output, the output is assumed to be linear. If the rendertarget is a sRGB format rendertarget then conversion from linear to sRGB will happen when the fragment is written to the rendertarget.

. For PNG textures I have to specify the format myself which is RGBA8_UNORM. I was surprised that the textures were not sRGB, but I double checked opening the images in VS and RenderDoc.


Why would you expect it to be sRGB when you are not uploading the texture as such ? Is RGBA8_UNORM a sRGB format ?

If the data in the texture is color data, chances are its sRGB. I would suggest read this post http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html as it may clear up a few questions you may have.

Share this post


Link to post
Share on other sites

Nice to see that my assumptions seem to be correct. The question was probably a bit ambiguous; the Direct3D version was likely correct, the "previous" version was just what I went with when getting Vulkan up and running and does not refer to the Direct3D version. I'm aware of what sRGB implies, I just wanted to know the particular rules of conversions in Vulkan.

 

I have also tested performing a fullscreen pass that simply outputs a gradient, and comparing to reference pictures of correct gamma indicates that something is indeed wrong. At the end of the day I'm none the wiser and have probably overlooked something. I will continue searching and see what can be the issue and look back here if somebody has chipped in with more suggestions or perhaps sources to conversion rules (in the spec I only found conversion rules regarding blitting, but nothing concerning shaders).

 

. For PNG textures I have to specify the format myself which is RGBA8_UNORM. I was surprised that the textures were not sRGB, but I double checked opening the images in VS and RenderDoc.


Why would you expect it to be sRGB when you are not uploading the texture as such ? Is RGBA8_UNORM a sRGB format ?

 

The format to use is just a remnant of when I was getting things up and running. I expected the texture to be sRGB because many images are stored with that encoding, but was surprised that it was not and could conclude that the texture was not the problem. I included that statement in the question for completeness as to what I considered when trying to figure out what might be erroneous.

Share this post


Link to post
Share on other sites

Your texture is almost certainly sRGB.

 

An image file normally contains a sequence of RGB triplets defining the colour of each pixel. However, this doesn't tell us exactly what 'shade' the colours are. A colour profile steps in here to define the spectral properties of the RGB values in the image - so without a profile the numbers are meaningless.

 

Fortunately sRGB is the colour space of the internet. This means it's now pretty much universally accepted that any untagged images files (i.e. they have no embedded profile) can be safely assumed to be sRGB.

Share this post


Link to post
Share on other sites

This topic is 406 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Forum Statistics

    • Total Topics
      628682
    • Total Posts
      2984196
  • Similar Content

    • By hiya83
      (Posted this in graphics forum too, which was perhaps the wrong forum for it)
      Hey, I was wondering if on mobile development (Android mainly but iOS as well if you know of it), if there is a GPUView equivalent for whole system debugging so we can figure out if the CPU/GPU are being pipelined efficiently, if there are bubbles, etc. Also slightly tangent question, but do mobile GPU's have a DMA engine exposed as a dedicated Transfer Queue for Vulkan?
      Thanks!
    • By hiya83
      Hey, I was wondering if on mobile development (Android mainly but iOS as well if you know of it), if there is a GPUView equivalent for whole system debugging so we can figure out if the CPU/GPU are being pipelined efficiently, if there are bubbles, etc. Also slightly tangent question, but do mobile GPU's have a DMA engine exposed as a dedicated Transfer Queue for Vulkan?
    • By mark_braga
      I am working on a project which needs to share render targets between Vulkan and DirectX12. I have enabled the external memory extension and now allocate the memory for the render targets by adding the VkExportMemoryInfoKHR to the pNext chain of VkMemoryAllocateInfo. Similarly I have added the VkExternalMemoryImageCreateInfo to the pNext chain of VkImageCreateInfo.
      After calling the get win32 handle function, I get some handle pointer which is not null (I assume it is valid).
      VkExternalMemoryImageCreateInfoKHR externalImageInfo = {}; if (gExternalMemoryExtensionKHR) { externalImageInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR; externalImageInfo.pNext = NULL; externalImageInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KH imageCreateInfo.pNext = &externalImageInfo; } vkCreateImage(...); VkExportMemoryAllocateInfoKHR exportInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR }; exportInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR; memoryAllocateInfo.pNext = &exportInfo; vkAllocateMemory(...); VkMemoryGetWin32HandleInfoKHR info = { VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR, NULL }; info.memory = pTexture->GetMemory(); info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR; VkResult res = vkGetMemoryWin32HandleKHR(vulkanDevice, &info, &pTexture->pSharedHandle); ASSERT(VK_SUCCESS == res); Now when I try to call OpenSharedHandle from a D3D12 device, it crashes inside nvwgf2umx.dll with the integer division by zero error.
      I am now lost and have no idea what the other handle types do.
      For example: How do we get the D3D12 resource from the VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR handle?
      I also found some documentation on this link but it doesn't help much.
      https://javadoc.lwjgl.org/org/lwjgl/vulkan/NVExternalMemoryWin32.html
      This is all assuming the extension works as expected since it has made it to the KHR
    • By dwatt
      I am trying to get vulkan on android working and have run into a big issue. I don't see any validation layers available. I have tried linking their libraries into mine but still no layers. I have tried compiling it into a library of my own but the headers for it are all over the place. Unfortunately , google's examples and tutorials are out of date and don't work for me. Any idea what I have to do to get those layers to work?
    • By mark_braga
      It seems like nobody really knows what is the correct behavior after window minimizes in Vulkan.
      I have looked at most of the examples (Sascha Willems, GPUOpen,...) and all of them crash after the window minimize event with the error VK_ERROR_OUT_OF_DATE either with an assertion during acquire image or after calling present. This is because we have to recreate the swap chain.
      I tried this but then Vulkan expects you to provide a swap chain with extents { 0, 0, 0, 0 }, but now if you try to set the viewport or create new image views with extents { 0, 0, 0, 0 }, Vulkan expects you to provide non-zero values. So now I am confused.
      Should we just do nothing after a window minimize event? No rendering, update, ...?
  • Popular Now