3

Let's say I have a compute shader that retrieves data from a Texture2DArray using the Id of the group like this:

Texture2DArray<float4> gTextureArray[2];
[numthreads(32, 1, 1)]
void Kernel(uint3 GroupID : SV_GroupID, uint3 GroupThreadID : SV_GroupThreadID)
{
    float3 tmp = gTextureArray[GroupID.x].Load(int4(GroupThreadID.x,GroupThreadID.x,0,0)).rgb;

    ....
}

And let's say I launch it like this deviceContext->Dispatch(2, 0, 0);

So, 2 groups, 32 threads each that read pixel values from a Texture2DArray. All the threads in GroupID.x = 0 will read values from gTextureArray[0] and all the threads in GroupID.y = 0 will read values from gTextureArray[1]. It turns out I can't compile that simple code, instead I get this compile error error X3512: sampler array index must be a literal expression

Now, I know I can do this instead:

Texture2DArray<float4> gTextureArray[2];
[numthreads(32, 1, 1)]
void Kernel(uint3 GroupID : SV_GroupID, uint3 GroupThreadID : SV_GroupThreadID)
{
    float3 tmp = float3(0,0,0);
    if(GroupID.x == 0)
        tmp = gTextureArray[0].Load(int4(GroupThreadID.x,GroupThreadID.x,0,0)).rgb;
    else if(GroupID.x == 1)
        tmp = gTextureArray[1].Load(int4(GroupThreadID.x,GroupThreadID.x,0,0)).rgb;

    ....
}

Or use a switch in case I have lots of groups so it doesn't look that much awful (it still does)

Notice how there is no warp divergence since all threads in each group will go one branch or the other. My question is, am I missing something here? Why does HLSL not support that kind of indexing since I can not see any divergence or other problems, at least in this case?

Gabriel C.
  • 97
  • 1
  • 10

1 Answers1

1

I'm not sure if you bind your pipeline correctly, but let's evaluate both cases.

When you have:

Texture2DArray<float4> gTextureArray[2];

You technically bind 2 texture array (one in slot 0, one in slot 1), so runtime is not able to switch shader resource slot dynamically.

The line above is the same as doing:

Texture2DArray<float4> gTextureArray0;
Texture2DArray<float4> gTextureArray1;

You effectively bind 2 different resources in both cases, hence why you can't dynamically switch.

In the case where you have a Texture Array with 2 slices, this becomes possible, you need to change your code by:

Texture2DArray<float4> gTextureArray;

[numthreads(32, 1, 1)]
void Kernel(uint3 GroupID : SV_GroupID, uint3 GroupThreadID : SV_GroupThreadID)
{
    float3 tmp = gTextureArray.Load(int4(GroupThreadID.x,GroupThreadID.x,GroupID.x,0)).rgb;

}

Z component is the slice index, so in that case that's perfectly possible.

mrvux
  • 8,523
  • 1
  • 27
  • 61
  • Yes. You're right. Using arrays of textures in the way I suggested seems to be just syntax sugar. Additional clarifications were given in this post http://www.gamedev.net/topic/655854-understanding-the-%E2%80%9Csampler-array-index-must-be-a-literal-expression%E2%80%9D-error-in-computeshaders/ – Gabriel C. Aug 08 '14 at 21:22
  • @catflier, how do I combine the Texture2d in c# to a Texture2DArray in hlsl? There's a missing link for me. Using a switch in hlsl to avoid the above exception, sux – Jeroen van Langen Jul 24 '17 at 17:36
  • @JeroenvanLangen this is quite easy at creation time to build a texture array, but answer would depend which c# wrapper you use (slimdx or sharpdx), it's also possible to do it from gpu generated resource with draw calls, compute passes or copy resource region. Maybe a question would be easier still (also helps people to have those answers not buried into comments). – mrvux Jul 25 '17 at 13:37