Search Unity

sRGB External Textures with Vulkan

Discussion in 'General Graphics' started by paezguerraalvaro, Dec 28, 2021.

  1. paezguerraalvaro

    paezguerraalvaro

    Joined:
    Oct 16, 2017
    Posts:
    9
    Hi, I hope I'm posting this in the correct sub-forum. I'm running into this issue with external textures in Vulkan that's driving me nuts. I hope someone can give me a hand.
    I'm trying to create some textures in Unity under Vulkan using a native plugin and pass them back to Unity so they are displayed. The idea here is to move the texture initialization and GPU upload steps off Unity's main thread to reduce FPS drop as much as possible. The data I'm passing to the plugin are the bytes returned by the Texture2D.GetRawTextureData() method. Once the plugin is done, a new texture is spawned in Unity's side by calling Texture2D.CreateExternalTexture().
    Now the problem is that the external texture's colors are kind of washed out, in what I assume is some kind of incorrect color correction. Below there's a screenshot of the texture I'm using to test this out. sRGB sampling is enabled and the format is set to BC7.

    external_texture_original_image.PNG

    Below there's a side-by-side comparison of the original image rendered as a normal texture (on the right) and the same image created as an external texture (on the left).

    external_texture_side_by_side_comparison.PNG

    Inspecting the newly created texture shows that Unity is correctly recognizing it as a BC7 texture encoded as sRGB (see picture below):

    external_textures_details.PNG

    I went ahead and tried to debug it using RenderDoc. From what I can gather, it seems the texture has the correct colors in memory and its format is BC7_SRGB, but for some reason it's being sampled as a UNORM texture. See the picture below where it says "BC7_SRGB Viewed as UNorm".

    render_doc_texture_details.PNG

    The resource inspector shows that the texture's Image View was initialized with the VK_FORMAT_BC7_UNORM_BLOCK. I'm also adding a screenshot of this.

    render_doc_image_view_details.PNG

    Any idea of why this could be happening? I would really appreciate any suggestions or tips.
    Some final random notes with more info:
    • This does not happen using the same texture and format in Direct3D11 (using the DXGI_FORMAT_BC7_UNORM_SRGB format flag in the plugin).
    • I have seen this same behavior in the editor in Windows 10, a standalone windows build and in Android too (Oculus Quest 2).
    • I have gotten similar results with other formats like ASTC and non-compressed formats like RGBA32.
    • When calling Texture2D.CreateExternalTexture() I have tried setting the "linear" argument to both true and false with the same results.
    • The Texture2D initialized using the native pointer returns BC7 as its TextureFormat and RGBA_BC7_SRGB as its GraphicsFormat.
    • Color Space is set to linear. If I set it to gamma, and use unorm formats, both textures are rendered in the same way. I would rather not switch to gamma, though.
    • I'm using Unity 2020.3.23f1 and Universal Render Pipeline 10.7.0.
     
  2. paezguerraalvaro

    paezguerraalvaro

    Joined:
    Oct 16, 2017
    Posts:
    9
  3. NicoLeyman

    NicoLeyman

    Unity Technologies

    Joined:
    Jun 18, 2019
    Posts:
    33
    Hi, Have you tried creating your Vulkan texture using
    VK_FORMAT_BC7_SRGB_BLOCK instead of
    VK_FORMAT_BC7_UNORM_BLOCK ? That should make sure the sampling on the GPU performs the correct conversion.
     
  4. paezguerraalvaro

    paezguerraalvaro

    Joined:
    Oct 16, 2017
    Posts:
    9
    Hi, thanks for taking the time to look into this.
    Yes, I'm initializing the image in the example in the op using VK_FORMAT_BC7_SRGB_BLOCK, but for some reason Unity is generating a view with VK_FORMAT_BC7_UNORM_BLOCK. I'm adding a screenshot of RenderDoc showing the VkCreateImageInfo used in the vkCreateImage call.

    native_plugin_texture_init_params.PNG

    After that I call Texture2D.CreateExternalTexture() using TextureFormat::BC7 and "linear" set to false. I checked the C# code reference repo (https://github.com/Unity-Technologies/UnityCsReference). If the code in that repo is correct, 'CreateExternalTexture' should call the internal Texture2D's constructor that would end up using GraphicsFormat::RGBA_BC7_SRGB:

    texture2d_internal_constructor.PNG

    The new Texture2D returns RGBA_BC7_SRGB as its GraphicsFormat. The view created by Unity, however, uses VK_FORMAT_BC7_UNORM_BLOCK for some reason. Here's a RenderDoc screenshot showing this:

    unity_unorm_view.PNG

    As far as I know I cannot make Unity use my own image views. Any ideas? Let me know if you need any more details.
     
  5. ValentinHm

    ValentinHm

    Unity Technologies

    Joined:
    Dec 10, 2020
    Posts:
    14
    Hi !
    Thanks for all the details :)
    Definitely looks like a bug, would you mind reporting it and attaching a repro project if possible ? That would speed up the process of it being fixed (https://unity3d.com/unity/qa/bug-reporting)
     
  6. MartinSher

    MartinSher

    Joined:
    Aug 22, 2017
    Posts:
    2
    I'm experiencing almost exactly the same problem, the only difference is that our texture is not BC7 encoded, it is just plain RGBA. paezguerraalvaro did you find a solution or workaround to your problem that doesn't involve changing the Color Space to linear? And if you reported the bug here: https://unity3d.com/unity/qa/bug-reporting, please can you link to it so we can follow along as well?
     
  7. paezguerraalvaro

    paezguerraalvaro

    Joined:
    Oct 16, 2017
    Posts:
    9
    Hi, @SpaceDude. No, I didn't report the bug. I told myself I was gonna do it eventually, but never did so. I'm not sure if Unity ever fixed this issue in a later LTS release. We are still using the 2020 LTS version (2020.3.36f1 to be exact). What I ended up doing was to enforce textures that are exported using our internal tooling to use a linear format instead of an sRGB one, so that they are correctly sampled by Unity at the end. I'm not sure if this is what you mean by changing the color space to linear (our project was already set to use linear format in the Player Settings anyway). I'm adding below the code that I'm using to do this:

    Code (CSharp):
    1.     public static Texture2D Linear(Texture2D texture)
    2.         {
    3.             GraphicsFormat originalFormat = texture.graphicsFormat;
    4.             GraphicsFormat linearFormat = GraphicsFormatUtility.GetLinearFormat(originalFormat);
    5.  
    6.             if(originalFormat == linearFormat) { return texture; }
    7.  
    8.             TextureCreationFlags creationFlags = texture.mipmapCount > 1 ? TextureCreationFlags.MipChain
    9.                                                                          : TextureCreationFlags.None;
    10.  
    11.             Texture2D linearTexture = new Texture2D(texture.width, texture.height, linearFormat, creationFlags);
    12.  
    13.             Color32[] pixels = texture.GetPixels32();
    14.  
    15.             for (int i = 0; i < pixels.Length; i++)
    16.             {
    17.                 pixels[i] = ((Color)pixels[i]).linear;
    18.             }
    19.  
    20.             linearTexture.SetPixels32(pixels);
    21.             linearTexture.Apply(updateMipmaps: true, makeNoLongerReadable: false);
    22.  
    23.             return linearTexture;
    24. }
     
  8. MartinSher

    MartinSher

    Joined:
    Aug 22, 2017
    Posts:
    2
    We are using 2021.3.11f1 and it seems the bug is still not fixed.

    > What I ended up doing was to enforce textures that are exported using our internal tooling to use a linear format instead of an sRGB one, so that they are correctly sampled by Unity at the end.

    I see, that makes sense. It's not so much an option for us because the texture is dynamically generated every frame or so and it would be too expensive to do the color conversion before registering it as an external texture.
     
  9. ValentinHm

    ValentinHm

    Unity Technologies

    Joined:
    Dec 10, 2020
    Posts:
    14
    Hello !
    We recently worked on some bugs were external textures were being set up with the wrong color space but there might be more going on here.
    Again, feel free to report the bug with a project allowing us to reproduce the issue so we can dive into it