D3d12 : d24_x8 format to rgba8?

Started by
9 comments, last by vlj 8 years, 2 months ago
I have a very very specific use case that sample depth texture (stored as d24 and 8 bits stencil) as an rgba8 components. There is no conversion involved, the texture is just reinterpreted and the depth value is obtained by a dot product of texel rgb with a constant vector (2^16,2^8,1).

Is this kind of operation supported with d3d? My testing shows that debug layer doesn't complain (d24x8 and rgba8 have same size but on the other hand the format are not straightforward) however with my Intel igpu the result is wrong. With an Nvidia card the result *looks* right but maybe it's just by luck.
Advertisement

I'm not sure if the API allows this or not... but I can say that D24S8 are not necessarily compatible to be aliased.

A lot of GPUs implement the D24 part as an R24_X8_UNORM and the S8 as a separate R8_UNORM. i.e. it's actually a 32bpp texture plus another 8bpp texture.

Traditionally, D3D and GL have only allowed you to read the D24 part, not the S8 part, to avoid this issue.

Also, depth and stencil almost always use fancy compression schemes, and need to be decompressed before you can read from them reliably --- so... if the API does allow you to perform this aliasing, the GPU driver is going to have to do a lot of work behind the scenes to copy the D24S8 data into an R8G8B8A8 for you.

D3D12 doesn't allow creating a shader resource view for a resource that was created with a different format. The only exception is if the resource was created with a "TYPELESS" format, in which case you can create an SRV using a format from that same "family". So for instance if you create a texture with R8G8B8A8_TYPELESS, you can create an SRV that reads it as R8G8B8A8_UNORM.

If you really wanted to, you can create two placed resources at the same memory offset within the same heap. However this is very unlikely to give you usable results, since the hardware is free to store the texture data in a completely different layout or swizzle pattern for resources that use different formats. You also can't keep depth buffers and normal textures in the same heap if the hardware reports RESOURCE_HEAP_TIER_1, which applies to older Nvidia hardware.

IIRC AMD GCN always stores the stencil and depth separately, so this hack won't work there.

IIRC AMD GCN always stores the stencil and depth separately, so this hack won't work there.

Yes they mentionned it on some twitter account, but then does GCN store 24 bits depth value as 32 bits if a 24 bits depth texture is requested ?

Since there is no performance bandwidth advantage since 24 bits needs to be stored in a 32 bits location and 8 bits are wasted the driver might as well promote d24x8 to d32 + r8 ?

[EDIT] Is it possible to copy depth component to a RGBA8 (possibly typeless) texture or do I have to use a shader to manually convert the float depth to int, do some bit shift operations and store component separatly ?

I think the correct way to access depth-stencil surface as texture (SRV) is to

1. create the resource as:

DXGI_FORMAT_R24G8_TYPELESS

2. create depth stencil surface as:

DXGI_FORMAT_D24_UNORM_S8_UINT

3. Create *two* separate SRVs for accessing depth and stencil parts of the surface of formats:

DXGI_FORMAT_R24_UNORM_X8_TYPELESS

DXGI_FORMAT_X24_TYPELESS_G8_UINT

You can only access depth from the first SRV (by reading red/x component of the texture as normalized float value) and only access stencil component from the second SRV (reading as unsigned integer).

This should work on all IHVs.

Yes but with DXGI_FORMAT_R24_UNORM_X8_TYPELESS format I can only access the 24 bits depth value, it's not splitted in 3x8 bits values.

Yes they mentionned it on some twitter account, but then does GCN store 24 bits depth value as 32 bits if a 24 bits depth texture is requested ?
Since there is no performance bandwidth advantage since 24 bits needs to be stored in a 32 bits location and 8 bits are wasted the driver might as well promote d24x8 to d32 + r8 ?


No, they store it as 24-bit fixed point with 8 bits unused. It only uses 32 bits if you request a floating point depth buffer, and they can't promote from fixed point -> floating point since the distribution of precision is different.

[EDIT] Is it possible to copy depth component to a RGBA8 (possibly typeless) texture or do I have to use a shader to manually convert the float depth to int, do some bit shift operations and store component separatly ?


You can only copy between textures that have the same format family.

Yes but with DXGI_FORMAT_R24_UNORM_X8_TYPELESS format I can only access the 24 bits depth value, it's not splitted in 3x8 bits values.

If you're using this format, you presumably have access to integer operations in your shaders -- are you just hoping to see a performance increase by not doing any bit shifting? I'm almost positive bit shifting three values isn't going to bog you down.

Yes they mentionned it on some twitter account, but then does GCN store 24 bits depth value as 32 bits if a 24 bits depth texture is requested ?
Since there is no performance bandwidth advantage since 24 bits needs to be stored in a 32 bits location and 8 bits are wasted the driver might as well promote d24x8 to d32 + r8 ?


No, they store it as 24-bit fixed point with 8 bits unused. It only uses 32 bits if you request a floating point depth buffer, and they can't promote from fixed point -> floating point since the distribution of precision is different.

Pretty much this. They cannot promote it for you since the behavior is very different. They must honour 24-bit integer precision.

As for the bandwidth, this is why AMD recommends that if you never use the stencil, don't ask for a depth buffer with stencil capabilities.

This topic is closed to new replies.

Advertisement