Понимание ошибки "индекс массива сэмплера должен быть буквальным выражением" в ComputeShaders

Допустим, у меня есть вычислительный шейдер, который извлекает данные из Texture2DArray с использованием идентификатора группы следующим образом:

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;

    ....
}

И скажем, я запускаю это так deviceContext->Dispatch(2, 0, 0);

Итак, 2 группы по 32 потока, каждая из которых считывает значения пикселей из Texture2DArray. Все потоки в GroupID.x = 0 будут считывать значения из gTextureArray[0], а все потоки в GroupID.y = 0 будут считывать значения из gTextureArray[1]. Оказывается, я не могу скомпилировать этот простой код, вместо этого я получаю эту ошибку компиляции error X3512: sampler array index must be a literal expression

Теперь я знаю, что могу сделать это вместо этого:

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;

    ....
}

Или используйте переключатель в случае, если у меня много групп, чтобы это не выглядело слишком ужасно (это все еще делает)

Обратите внимание, что нет расхождения деформации, поскольку все потоки в каждой группе будут идти в одну или другую ветвь. У меня вопрос, я что-то здесь упускаю? Почему HLSL не поддерживает такого рода индексацию, поскольку я не вижу никаких расхождений или других проблем, по крайней мере, в этом случае?

1 ответ

Я не уверен, правильно ли вы связали свой конвейер, но давайте оценим оба случая.

Когда у тебя есть:

Texture2DArray<float4> gTextureArray[2];

Технически вы связываете 2 текстурных массива (один в слоте 0, один в слоте 1), поэтому среда выполнения не может динамически переключать слот ресурсов шейдера.

Строка выше аналогична выполнению:

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

Вы эффективно связываете 2 разных ресурса в обоих случаях, поэтому вы не можете динамически переключаться.

В случае, когда у вас есть массив текстур с 2-мя слайсами, это становится возможным, вам нужно изменить код следующим образом:

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 является индексом среза, так что в этом случае это вполне возможно.

Другие вопросы по тегам