Direct3D11:“梯度指令在循环中使用,迭代次数不同,强制循环展开”,警告:X3570

时间:2019-06-13 13:01:55

标签: directx direct3d hlsl

我正在使用Direct3D 11和Visual Studio 2015开发图形引擎。在用于主绘制调用的HLSL着色器中,我使用百分比-更近距离过滤对定向和点光源的阴影贴图进行采样,即对一个小的目标阴影贴图纹理周围的正方形区域,并对结果求平均以得到柔和的阴影。现在,每次对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 个答案:

答案 0 :(得分:2)

梯度函数是所有纹理采样方法,它们可以自行确定所使用的Mip级别,例如您所使用的方法Sample。因此,它们在内部使用ddxdoc)和ddydoc)。片段在gpu上以2x2块计算,因此它们可以相互比较纹理坐标的差异。差异越大,则使用的mip-map级别越高。使用动态分支时,此方法不再起作用,因为不能保证每个片段都使用相同的计算路径,因此梯度函数在动态分支中不起作用。当循环使用分支时,编译器必须使它们变为静态才能使用梯度函数。在这种情况下,可以通过展开来完成此操作,因为循环始终相同。编译器已经检测到它,并通过自动编写所有步骤来编写非分支代码来编译您的循环。使用[unroll]doc)语句,可以提示编译器这样做并禁止显示警告。

代码的另一种方法是使用不是梯度函数的采样方法,例如SampleLeveldoc),在其中传递所需的mip-map级别(本例中为0)因为您的阴影贴图没有mip-map-levels),并且gpu不必确定它。据我所知,对性能的影响可以忽略不计,因为这种情况发生在非常低​​的水平上,大多数功能在gpu上的处理速度都一样快,但是也许您应该自己进行测试。

另一种不适用于您的情况,但另一种用于提取文本像素的非渐变方法是Loaddoc),可通过整数texel索引直接获取特定的texel。

答案 1 :(得分:0)

如查克·沃尔本(Chuck Walbourn)所述,在for循环之前添加[unroll]语句可修复警告。这种警告类型基本上是编译器会通知您的循环无法展开,或者这样做的执行效率较低(可以在Microsoft documentation for the HLSL for-loop中进行读取)。我认为可以放心接受。