Direct3D11:"gradient instruction used in a loop with varying iteration, forcing loop to unroll",警告:X3570
Direct3D11: "gradient instruction used in a loop with varying iteration, forcing loop to unroll", warning: X3570
我正在使用 Direct3D 11 和 Visual Studio 2015 开发图形引擎。在主要绘制调用的 HLSL 着色器中,我使用百分比更近过滤对定向光源和点光源的阴影贴图进行采样,即我在目标阴影贴图纹素周围采样一个小正方形区域并对结果进行平均以获得柔和的阴影。现在,每次调用 shadowMap_.Sample(...) 都会创建一个警告:"gradient instruction used in a loop with varying iteration, forcing loop to unroll" (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);
}
代码仍然可以正常工作,但我收到了大量此类警告,不知道这是否会对性能产生相关影响。非常感谢有关警告的任何进一步信息以及可以采取的措施。
提前致谢。
正如 Chuck Walbourn 所说,在 for 循环之前添加 [unroll] 语句可以修复警告。这种类型的警告基本上是编译器通知您无法展开循环或者这样做会降低性能(可以在 Microsoft documentation for the HLSL for-loop 中阅读)。我认为这可以被安全地接受。
梯度函数都是自己决定使用的mip-level的纹理采样方法,比如你使用的方法Sample
。因此,他们使用 ddx
(doc) and ddy
(doc) internally. Fragments are computed on the gpu in 2x2 chunks, so they can compare the difference in the texture coordinate with each other. The larger the difference the higher mip-map-level is used. With dynamic branching this method no longer works as it is not assured that each fragment uses the same computation path, so gradient functions don't work within dynamic branches. As loops are using branching, the compiler has to make them static to use gradient functions. This is done by unrolling in you case as the loops are always the same. The compiler already detected it and compiles your loops with writing all steps after another automatically to make non-branching code. With the [unroll]
(doc) 语句,您可以提示编译器这样做并抑制警告。
代码的另一种方法是使用不是梯度函数的采样方法,例如 SampleLevel
(doc),您在其中传递所需的 mip-map-level(0 in你的情况,因为你的阴影贴图没有 mip-map-levels) 并且 gpu 不必确定它。据我所知,性能影响可以忽略不计,因为这发生在非常低的水平上,大多数功能在 gpu 上的处理速度同样快,但也许你应该做自己的测试。
一个不适用于您的情况的补充,但另一种获取文本元素的非梯度方法是 Load
(doc) 通过整数纹理元素索引直接获取特定的纹理元素。
我正在使用 Direct3D 11 和 Visual Studio 2015 开发图形引擎。在主要绘制调用的 HLSL 着色器中,我使用百分比更近过滤对定向光源和点光源的阴影贴图进行采样,即我在目标阴影贴图纹素周围采样一个小正方形区域并对结果进行平均以获得柔和的阴影。现在,每次调用 shadowMap_.Sample(...) 都会创建一个警告:"gradient instruction used in a loop with varying iteration, forcing loop to unroll" (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);
}
代码仍然可以正常工作,但我收到了大量此类警告,不知道这是否会对性能产生相关影响。非常感谢有关警告的任何进一步信息以及可以采取的措施。
提前致谢。
正如 Chuck Walbourn 所说,在 for 循环之前添加 [unroll] 语句可以修复警告。这种类型的警告基本上是编译器通知您无法展开循环或者这样做会降低性能(可以在 Microsoft documentation for the HLSL for-loop 中阅读)。我认为这可以被安全地接受。
梯度函数都是自己决定使用的mip-level的纹理采样方法,比如你使用的方法Sample
。因此,他们使用 ddx
(doc) and ddy
(doc) internally. Fragments are computed on the gpu in 2x2 chunks, so they can compare the difference in the texture coordinate with each other. The larger the difference the higher mip-map-level is used. With dynamic branching this method no longer works as it is not assured that each fragment uses the same computation path, so gradient functions don't work within dynamic branches. As loops are using branching, the compiler has to make them static to use gradient functions. This is done by unrolling in you case as the loops are always the same. The compiler already detected it and compiles your loops with writing all steps after another automatically to make non-branching code. With the [unroll]
(doc) 语句,您可以提示编译器这样做并抑制警告。
代码的另一种方法是使用不是梯度函数的采样方法,例如 SampleLevel
(doc),您在其中传递所需的 mip-map-level(0 in你的情况,因为你的阴影贴图没有 mip-map-levels) 并且 gpu 不必确定它。据我所知,性能影响可以忽略不计,因为这发生在非常低的水平上,大多数功能在 gpu 上的处理速度同样快,但也许你应该做自己的测试。
一个不适用于您的情况的补充,但另一种获取文本元素的非梯度方法是 Load
(doc) 通过整数纹理元素索引直接获取特定的纹理元素。