Sign in to follow this  
lomateron

HLSL reading outside array safe?

Recommended Posts

I have an ID3D10EffectVectorVariable in HLSL code it looks like this:

int4 array;

float4 VS()
{
   uint x = 0;
   //"x" is loaded from texture can be a value bigger than 3
   int grab = array[x];
   if(x > 3)
   {
      grab = 0;
   }

   //blablabla
}

is this code safe?

Edited by lomateron

Share this post


Link to post
Share on other sites
It's not going to crash, no. If you look at the assembly you can see what will happen -- in vs_4_0 it will do a bunch of masking nonsense and the final result will be sort of garbage with an out of bounds index.

Share this post


Link to post
Share on other sites

It's not going to crash, no. If you look at the assembly you can see what will happen -- in vs_4_0 it will do a bunch of masking nonsense and the final result will be sort of garbage with an out of bounds index.

 

I have played around with DX12 with shader model 5.1, and some of my original working program (I ported them to DX12 with sm5.1) will cause GPU crashing. And later I found out it's actually caused by reading out of boundary of UAVs. So I am not sure in DX12 with sm5.1, whether the out of bound behavior will cause crash or not. Or it depends on your resource or UAV configuration.

 

Also I haven't tried this with just arrays.

 

But it will be great if somebody could verify that...

Edited by Mr_Fox

Share this post


Link to post
Share on other sites

To be clear the example posted is a float4, not a buffer. So, the indexing is into the xyzw components in this case.

 

Sorry, I should start another thread about my concern: so basically I found in DX11 and before, out of bound access to UAV won't cause any trouble, it just return 0. But in DX12, my case, it will crash GPU. So any idea what changed in DX12 in term of UAV access?

 

Thanks 

Share this post


Link to post
Share on other sites

It's quite difficult to get that "just return 0" behavior that D3D11 guaranteed. I'm still not understanding the scenario. Are you reading beyond the end of the buffer (e.g. buffer is 100 bytes, you're reading byte 101), or are you reading beyond the end of the bound array (e.g. array declared to have N elements, but only M are bound, you're reading N+1 or M+1)?

 

In the first case, that should work as long as you're using descriptors from a table. Root descriptors don't contain size information, so out-of-bounds access can cause a page fault/crash.

 

In the second case, if you're reading M+1, you're reading from the descriptor that's M+1 past the start of the table. That descriptor needs to have valid contents in order to get defined behavior. If you're reading it as a UAV, there needs to be a UAV descriptor there. It actually needs to be even more specific depending on hardware - if you're reading a buffer UAV, there needs to be a buffer UAV descriptor there. It doesn't need to have a valid resource pointer, you can initialize it with a null resource to get 0s on read, but if the type doesn't match, you can cause a hang.

Share this post


Link to post
Share on other sites

It's quite difficult to get that "just return 0" behavior that D3D11 guaranteed. I'm still not understanding the scenario. Are you reading beyond the end of the buffer (e.g. buffer is 100 bytes, you're reading byte 101), or are you reading beyond the end of the bound array (e.g. array declared to have N elements, but only M are bound, you're reading N+1 or M+1)?

 

In the first case, that should work as long as you're using descriptors from a table. Root descriptors don't contain size information, so out-of-bounds access can cause a page fault/crash.

 

In the second case, if you're reading M+1, you're reading from the descriptor that's M+1 past the start of the table. That descriptor needs to have valid contents in order to get defined behavior. If you're reading it as a UAV, there needs to be a UAV descriptor there. It actually needs to be even more specific depending on hardware - if you're reading a buffer UAV, there needs to be a buffer UAV descriptor there. It doesn't need to have a valid resource pointer, you can initialize it with a null resource to get 0s on read, but if the type doesn't match, you can cause a hang.

 

Thanks Jesse, that's very helpful.

In my case, I have a volume buffer for volume rendering, and have shader access SRV with indices. in some cases, when calculating the indices, rounding error will bring it actually out of bound (width*height*depth), D3D11 have no problem with it. But after I port it to dx12 (yes, I bound the volume buffer srv as root srv) the out of bound access on that buffer will cause crash....

 

But does that means in D3D11, the driver will do a boundary check when you read resource?  So basically, how d3d11 can guarantee return 0 when access out of boundary (just curious)

Share this post


Link to post
Share on other sites

It's frequently a function that the hardware does automatically, though sometimes it's implemented in the shader by the driver. Descriptor table bindings require that same out-of-bounds check that D3D11 had. As long as your descriptor has correct bounds, then out-of-bounds reads should return 0.

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