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