Advertisement

Shader doesn't work on AMD GPUs with latest driver

Started by April 04, 2019 03:01 PM
17 comments, last by Vilem Otte 5 years, 10 months ago

Hi,

I use the following shader (HLSL) to scale positions, normals, and depth for post processing:

 


Texture2D normalTexture : register(t0);
Texture2D positionTexture : register(t1);
Texture2D<float> depthTexture : register(t2);


static const uint POST_PROCESSING_SCALING_MASK = 0xC0;
static const uint POST_PROCESSING_SCALING_FULL = 0x00;
static const uint POST_PROCESSING_SCALING_HALF = 0x40;
static const uint POST_PROCESSING_SCALING_QUARTER = 0x80;


cbuffer PixelBuffer{
    float fogStart;
    float fogMax;
    uint Flags;
    float Gamma;


    float3 fogColor;
    float SpaceAlpha;


    float FrameTime;
    float MinHDRBrightness;
    float MaxHDRBrightness;
    float ScreenWidth;


    float3 SemiTransparentLightColor;
    float ScreenHeight;


    float SpaceAlphaFarAway;
    float SpaceAlphaNearPlanets;
    float HDRFalloffFactor;
    float InverseGamma;


    float3 CameraLiquidColor;
    float CameraLiquidVisualRange;


    float CameraInLiquidMinLerpFactor;
    float CameraInLiquidMaxLerpFactor;
    float MinCloudBrightness;
    float MaxCloudBrightness;


    float4 BorderColor;


    float3 SunColor;
    float padding0;
};


struct PixelInputType{
    float4 position : SV_POSITION;
};



struct PixelOutputType{
    float4 normal : SV_Target0;
    float4 position : SV_Target1;
    float depth : SV_Depth;
};


PixelOutputType main(PixelInputType input){
    PixelOutputType output;
    const uint ScalingFlag = (Flags & POST_PROCESSING_SCALING_MASK) >> 6;


    uint3 TexCoords = uint3(uint2(input.position.xy) << ScalingFlag, 0);
    const uint Max = (1 << ScalingFlag) << ScalingFlag;
    uint UsedIndex = 0xFFFFFFFF;
    for (uint i = 0; i < Max && i < 16; ++i) {
        const uint3 CurrentTexCoords = TexCoords + uint3(i & ((1 << ScalingFlag) - 1), i >> ScalingFlag, 0);
        output.position = positionTexture.Load(CurrentTexCoords);
        if (output.position.w >= 0.0f) {    
            UsedIndex = i;
            break;            
        }        
    }
    if (UsedIndex == 0xFFFFFFFF) {
        output.normal = float4(0, 0, 0, 0);
        output.depth = 1.0f;
        discard;
    }
    else {
        const uint3 CurrentTexCoords2 = TexCoords + uint3(UsedIndex & ((1 << ScalingFlag) - 1), UsedIndex >> ScalingFlag, 0);
        output.normal = normalTexture.Load(CurrentTexCoords2);
        output.depth = depthTexture.Load(CurrentTexCoords2);
    }
    return output;
}

 

It doesn't work with the latest drivers on AMD graphics cards, neither on my laptop (R7 M270) nor one of my friend's computers (RX 480).

It works perfectly on Nvidia/Intel GPUs and it worked with older drivers on my laptop, too.

On AMD GPUs, it outputs wrong data, i.e. output.position.w < 0 even though that is impossible (if it is < 0, UsedIndex will be 0xFFFFFFFF, therefore the pixel will be discarded). If I manually set output.position.w = 0 in both of the branches on (UsedIndex == 0xFFFFFFFF), it outputs 0 in the w component. If I set it in only one of the branches (doesn't matter which one), then output.position.w is negative in the output.

The other output (positions.xyz, normals.xyz, and depth) seems to be correct, but I'm not sure about normals.w.

It literally makes no sense and I think it's a driver bug, what can I do?

Cheers,

Magogan

Edit: If I add the following code before returning output, it gets even weirder:


if (output.position.w < 0) {
	output.position.w = 0;
}
else {
	output.position.w = 1;	
}

After that, output.position.w is neither 0 nor 1, but something such that it is not >= 0, so probably NAN or negative. WTF?

How do you declare your GBuffer multiple render target buffers?

If shader is compiled and linked, it should not be the source of problem at all.

Advertisement
1 minute ago, JohnnyCode said:

How do you declare your GBuffer multiple render target buffers?

What?

1 minute ago, JohnnyCode said:

If shader is compiled and linked, it should not be the source of problem at all.

You would think so... And you would be wrong...

My question was quite clear, your pixel function outputs to 3 render targets of likely float components per channels.

You also sample one float per component texture.

If you think modifying your shader will solve your issue while it was succefully compiled, good luck then.

Just now, JohnnyCode said:

My question was quite clear, your pixel function outputs to 3 render targets of likely float components per channels.

Yes? It just works like that. I don't understand the question.

if its driver version related, it could be driver bug, you can write to amd support about it.

Advertisement
Just now, joeblack said:

if its driver version related, it could be driver bug.

I'm like 80% sure it is, but how do I get AMD to fix it, without my game being as popular as The Witcher or Battlefield? How can I find a workaround in the meantime?

you can write to amd forums/support mail. it looks that problem is in positiontexture. Have you checked content of that texture ?

2 minutes ago, joeblack said:

you can write to amd forums/support mail.

And you think they will fix it?

2 minutes ago, joeblack said:

it looks that problem is in positiontexture. Have you checked content of that texture ?

Yes, the texture is correct. Otherwise it wouldn't work with Nvidia/Intel GPUs (and an older version of the AMD driver on my laptop). And even if the texture is not correct, that wouldn't explain the behavior I observed.

Well it depends, on AMD speed.

What is format of texture ? did you checked shader that is writing to it ?

This topic is closed to new replies.

Advertisement