Direct3D11: «инструкция градиента, используемая в цикле с изменяющейся итерацией, заставляющая цикл развернуться», предупреждение: X3570 - PullRequest
1 голос
/ 13 июня 2019

Я работаю над графическим движком, использующим Direct3D 11 и Visual Studio 2015. В шейдерах HLSL для основных вызовов отрисовки я пробую карты теней для направленного и точечного источников света с процентной фильтрацией ближе, т.е. квадратную область вокруг целевой карты теней texel и усредните результаты, чтобы получить мягкие тени. Теперь каждый вызов shadowMap_.Sample (...) создает предупреждение: "инструкция градиента, используемая в цикле с изменяющейся итерацией, заставляющая цикл развернуться" (X3570) . Я хочу исправить это или, если это невозможно, скрыть предупреждение, поскольку оно полностью заполняет мой вывод предупреждения.

Я попытался найти сообщение об ошибке в Интернете и не смог найти дальнейших описаний. Я даже не смог найти объяснения, что такое инструкция по градиенту. Я проверил документацию Microsoft на наличие другого сэмплера или функции сэмплирования, которая позволяет мне заменить цикл на встроенную функцию сэмплирования, но ничего подобного также не нашел. Вот функция, которую я использую для выборки моих карт теневого куба для точечных источников света:

float getPointShadowValue(in uint index, in float3 worldPosition)
{
    // (Half-)Radius for percentage closer filtering
    int hFilterRadius = 2;

    // Calculate the vector inside the cube that points to the fragment
    float3 fragToLight = worldPosition.xyz - pointEmitters_[index].position.xyz;

    // Calculate the depth of the current fragment
    float currentDepth = length(fragToLight);

    float sum = 0.0;
    for (float z = -hFilterRadius; z <= hFilterRadius; z++)
    {
        for (float y = -hFilterRadius; y <= hFilterRadius; y++)
        {
            for (float x = -hFilterRadius; x <= hFilterRadius; x++)
            {
                // Offset the currently targeted cube map texel and sample at that position
                float3 off = float3(x, y, z) * 0.05;
                float closestDepth = pointShadowMaps_.Sample(sampler_, float4(fragToLight + off, index)).x * farPlane_;
                sum += (currentDepth - 0.1 > closestDepth ? 1.0 : 0.0);
            }
        }
    }
    // Calculate the average and return the shadow value clamped to [0, 1]
    float shadow = sum / (pow(hFilterRadius * 2 + 1, 3));
    return min(shadow, 1.0);
}

Код все еще работает нормально, но я получаю огромное количество этих предупреждений и не знаю, вызывает ли это соответствующее снижение производительности. Будем весьма благодарны за любую дополнительную информацию о предупреждении и о том, что с ним можно сделать.

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 17 июня 2019

Функция градиента - это все методы выборки текстур, которые сами определяют используемый уровень mip, например, используемый вами метод Sample.Поэтому они используют ddx ( doc ) и ddy ( doc ) для внутреннего использования.Фрагменты вычисляются на графическом процессоре в виде фрагментов 2x2, поэтому они могут сравнивать разницу в координатах текстуры друг с другом.Чем больше разница, тем выше уровень mip-map.При динамическом ветвлении этот метод больше не работает, так как не гарантируется, что каждый фрагмент использует один и тот же путь вычисления, поэтому функции градиента не работают в динамических ветвлениях.Поскольку циклы используют ветвление, компилятор должен сделать их статичными, чтобы использовать функции градиента.Это делается путем развертывания в вашем случае, так как циклы всегда одинаковы.Компилятор уже обнаружил это и компилирует ваши циклы с автоматической записью всех шагов за другим, чтобы создать код без ветвления.С помощью оператора [unroll] ( doc ) вы можете дать подсказку компилятору и подавить предупреждения.

Еще один способ для вашего кода - использовать методы выборки, которые не являются градиентными функцияминапример, SampleLevel ( doc ), где вы проходите желаемый уровень mip-map (в вашем случае 0, поскольку у карты теней нет уровней mip-map), а у gpu нетдолжен определить это.Насколько я знаю, влияние на производительность незначительно, так как это происходит на очень низком уровне, когда большинство функций обрабатываются одинаково быстро на графическом процессоре, но, возможно, вам следует провести собственные тесты.

Одно дополнение, которое не относится кв вашем случае, но еще один не градиентный метод для извлечения textels - это Load ( doc ) для непосредственного извлечения определенного texel по целочисленному индексу texel.

0 голосов
/ 17 июня 2019

Как уже сказал Чак Уолборн, добавление оператора [unroll] перед циклом for исправляет предупреждения.Этот тип предупреждения в основном является компилятором, информирующим вас о том, что цикл не может быть развернут, или он будет менее производительным (как можно прочитать в документации Microsoft для цикла HLSL for-loop ).Я предполагаю, что это может быть безопасно принято.

...