Sign in to follow this  
gduser418

How to read DXGI_FORMAT_NV12 or DXGI_FORMAT_P010 texture in Direct3D shader

Recommended Posts

I have a 2D texture in DXGI_FORMAT_NV12 or some other chroma subsampled texture (4:2:0 here) in DirectX. How can I read the texture values to retrieve the corresponding YUV value? Here the data is layed out as planar in Y component and UV in another plane interleaved.

Share this post


Link to post
Share on other sites

Thank you very much for the code. On a side note, how can I output 10 bit data to the back buffer? The back buffer could be set to R10G10B10A2_UNORM format, not R16G16B16A16_UNORM format. In the shader the output is float4. If I just output float4, will Direct3D convert it to R10G10B10A2 automatically?

Share this post


Link to post
Share on other sites

Correct. You should also be able to use R16G16B16A16_FLOAT if you'd like.

 

My question was, I could not use R16G16B16A16_FLOAT as back buffer format, it is not supported. But R10G10B10A2_UNORM is ok. In the shader I simply write the output as float4, and it seems the result is fine. Did DirectX magically convert it to R10G10B10A2_UNORM at the output? I want to make sure the output is 10 bit.

Share this post


Link to post
Share on other sites

Could you share the SRV creation code? If there are two SRVs, should it specify where the Y and UV start from? I don't see there is a way in the CreateShaderResourceView to describe the offset. In P010 case, I suppose the Y format should be R16_UNORM, and UV format should be R16G16_UNORM.

 

For 4:2:0, g_SubsampleFactorX=1.f, g_SubsampleFactorY=0.5f, is it correct?

Share this post


Link to post
Share on other sites

The SRV creation code is not really centralized to the point that I can share it from this particular source.

 

The two SRVs are distinguishable just by the format of the view. One channel indicates Y, while two channels indicates UV. For 8 bit planar YUV, you're only allowed to specify formats of R8 and R8G8. For 10 or more bits, the only allowed formats are R16 and R16G16.

 

For the subsample factors:

The pitch is the same between the Y and UV planes, but the UV plane has two components where Y only has 1. So while the bit-width of the UV plane is the same as the Y plane, the logical width (number of pixels) in the UV plane is half.

g_SubsampleFactorX = 0.5f, g_SubsampleFactorY = 0.5f.

 

https://en.wikipedia.org/wiki/Chroma_subsampling#Sampling_systems_and_ratios has a description. 4:2:0 is half vertical and half horizontal resolution.

Share this post


Link to post
Share on other sites

What I don't understand is, the underlying texture (NV12 or P010) is one object, if the two SRVs point to the same data, shouldn't the UV load have an offset to Y?

 

When YCoords = (0, 0), UVCoords will be (0, 0) per your equation. How could it be correct when UV is actually (width, height) away in the data laid out?

Share this post


Link to post
Share on other sites

I understand your confusion. The offset is implied by the format of the view. A view with a format with one channel means you're looking at the Y plane, at offset 0. When your view format has two channels, it means you're looking at the UV plane, at offset 1.

 

You can also take a look at ID3D11Device3::CreateShaderResourceView1, where the texture2D descs for the view have an additional parameter for a plane index. This is the offset you're looking for, but it can be inferred just based on the view format.

Share this post


Link to post
Share on other sites

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