Use DXGI_FORMAT_R8G8B8A8_UINT texture format in pixel shader

Started by
5 comments, last by leonard2012 11 years, 11 months ago
Hi all,
I tried to draw a 2D texture of R8G8B8A8_UINT format. Each texel is packed with the code

UINT *pt = texels;
unsigned char *pp = (unsigned char *)pixels;
for ( int i = 0; i < height; i++ )
for ( int j = 0; j < width; j++ ) {
r = UINT(*pp++);
g = UINT(*pp++);
b = UINT(*pp++);
a = UINT(*pp++);
*pt++ = r<<24 | g<<16 | b<<8 | a;
}

and unpacked in pixel shader like

float4 texPS(float4 posH : SV_POSITION,
float2 oTexC : TEXCOORD) : SV_Target
{
uint diffuse = gDiffuseMap.Sample( gTextureSampler, oTexC );
uint a = (diffuse & 0x000000FF);
uint b = (diffuse & 0x0000FF00) >> 8;
uint g = (diffuse & 0x00FF0000) >> 16;
uint r = (diffuse & 0xFF000000) >> 24;
return float4(r, g, b, a) / 255.0f;
}

Unfortunately this does not work, the error message triggered by DrawIndex function is:
[indent=1]D3D10: ERROR: ID3D10Device::DrawIndexed: The resource return type for component 0 declared in the shader code (FLOAT) is not compatible with the resource type bound to slot 0 of the Pixel Shader unit (UINT). This is invalid if the shader actually uses the view (e.g. it is not skipped due to shader code branching). [ EXECUTION ERROR #361: DEVICE_DRAW_RESOURCE_RETURN_TYPE_MISMATCH ]
[indent=1]D3D10: ERROR: ID3D10Device::DrawIndexed: The Shader Resource View in slot 0 of the Pixel Shader unit is using the Format (R8G8B8A8_UINT). This format does not support 'Sample', 'SampleLevel', 'SampleBias' or 'SampleGrad', at least one of which is being used on the Resource by the shader. This is invalid if the shader actually uses the view (e.g. it is not skipped due to shader code branching). [ EXECUTION ERROR #371: DEVICE_DRAW_RESOURCE_FORMAT_SAMPLE_UNSUPPORTED ]
I change the texture format to R32_UINT but still fails with similar error message:
[indent=1]D3D10: ERROR: ID3D10Device::DrawIndexed: The resource return type for component 0 declared in the shader code (FLOAT) is not compatible with the resource type bound to slot 0 of the Pixel Shader unit (UINT). This is invalid if the shader actually uses the view (e.g. it is not skipped due to shader code branching). [ EXECUTION ERROR #361: DEVICE_DRAW_RESOURCE_RETURN_TYPE_MISMATCH ]
[indent=1]D3D10: ERROR: ID3D10Device::DrawIndexed: The Shader Resource View in slot 0 of the Pixel Shader unit is using the Format (R32_UINT). This format does not support 'Sample', 'SampleLevel', 'SampleBias' or 'SampleGrad', at least one of which is being used on the Resource by the shader. This is invalid if the shader actually uses the view (e.g. it is not skipped due to shader code branching). [ EXECUTION ERROR #371: DEVICE_DRAW_RESOURCE_FORMAT_SAMPLE_UNSUPPORTED ]

It seems that Texture2D::Sample function does not support R32_UINT and R8G8B8A8_UINT format.
Advertisement
The change from R8G8B8A8_UINT to R32_UINT is inspired by this post:http://www.gamedev.net/topic/605356-r8g8b8a8-texture-format-in-compute-shader/. But it does not work in my case.
To sample a UINT format, you need to declare your texture with a uint return type in your shader. The default is float4, which is why you're getting those errors.

For R8G8B8A8_UINT, you'll get 4 UINT's in your shader (not 1 uint, which is what your shader code is assuming). So you want to declare your texture like this:

Texture2D<uint4> gDiffuseMap;


For R32_UINT, you would declare it like this:

Texture2D<uint> gDiffuseMap;


However in you're just going to divide by 255 to get a [0,1] format, then you can just use a UNORM format and the texture unit will do the conversion for you.
Thanks for your response, MJP. I followed your method to use R32_INT texture format. The packing code is the same as in my first post. This is part of the effect file:

Texture2D<uint> gDiffuseMap;
SamplerState gTextureSampler
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
uint texPS(float4 posH : SV_POSITION,
float2 oTexC : TEXCOORD) : SV_Target
{
return gDiffuseMap.Sample( gTextureSampler, oTexC );
}


However this effect file fail to compile:

2>E:\Projects\micaps\private\micaps\render\directx\shader.fx(70,5): error X4582: cannot sample from non-floating point texture formats.

2>E:\Projects\micaps\private\micaps\render\directx\shader.fx(84,25): There was an error compiling expression

Yeah you have to use Load or the [] operator with integer formats, since filtering isn't supported.

Like I said earlier if you use R8G8B8A8_UNORM format instead and declare your Texture2D with float4 return type then you can use Sample and get the result you're expecting without having to manually unpack in the shader.
If anyone ever finds the need to do this in OpenGL, you would simply use a [g]usampler2D with texture2DLod(coord, 0).a

Yeah you have to use Load or the [] operator with integer formats, since filtering isn't supported.

Like I said earlier if you use R8G8B8A8_UNORM format instead and declare your Texture2D with float4 return type then you can use Sample and get the result you're expecting without having to manually unpack in the shader.

Thank you MJP, I use R8G8B8A8_UNORM format and it works. The pixel shader code in effect file is clean and simple

Texture2D gDiffuseMap;
float4 texPS(float4 posH : SV_POSITION,
float2 oTexC : TEXCOORD) : SV_Target
{
return gDiffuseMap.Sample( gTextureSampler, oTexC );
}

This topic is closed to new replies.

Advertisement