使用动态索引时 DirectX 12 中出现奇怪的纹理故障

Weird texture glitch in DirectX 12 when using dynamic indexing

最近,我在我的引擎中实现了纹理加载。 但是贴图有时会有一些小问题。

问题如下图所示。 enter image description here

这是用 AMD R9 380 测试的。 我还尝试在 Intel Graphic HD 4600 上执行我的程序,但它什么也没画。 (未显示几何图形。)

我的着色器代码:

struct MaterialData
{
    float4 gDiffuseAlbedo;
    float3 gFresnelR0;
    float  gRoughness;
    float4x4 gMatTransform;
    uint gDiffuseMapIndex;
    uint MaterialPad0;
    uint MaterialPad1;
    uint MaterialPad2;
};
StructuredBuffer<MaterialData> gMaterialData : register(t1, space1);

// texture array for dynamic indexing
// gMaxNumOfTextures is set to 16 at now
Texture2D gCommonTexture[gMaxNumOfTextures] : register(t3);

// in my pixel shader:
float4 diffuseAlbedoMap = gCommonTexture[matData.gDiffuseMapIndex].Sample(gsamAnisotropicWrap, pin.TexC) * matData.gDiffuseAlbedo;

我已经仔细检查了 matData.gDiffuseMapIndex,它是正确的。

我尝试了所有方法来解决这个问题,但都没有成功。 直到我将代码修改为:

// in my pixel shader:
float4 diffuseAlbedoMap = float4(0,0,0,0);

uint realMatIndex;
for(realMatIndex = 0;realMatIndex < gMaxNumOfTextures;realMatIndex++)
    if(realMatIndex == matData.gDiffuseMapIndex)
    {
        diffuseAlbedoMap = gCommonTexture[matData.gDiffuseMapIndex].Sample(gsamAnisotropicWrap, pin.TexC) * matData.gDiffuseAlbedo;
        break;
    }

这一切正常!

我的 R9 380 没有故障。

并且所有几何图形都在 HD 4600 上正常显示。

但是为什么!?

为什么我需要使用for循环再次检查索引以防止出现故障?

(如果我使用更多纹理,这可能无法有效地工作。)

什么会导致这个问题?

这个问题我想了一个晚上都没找到答案

谢谢!

完整着色器代码: enter link description here

显然,您需要使用 NonUniformIndex(matData.gDiffuseMapIndex) 让编译器知道索引是不统一的。

这是因为在 GCN 硬件上,纹理描述符存储在整个 wave 共享的标量寄存器中。内在函数执行您所做的,一个循环,但是通过在所有线程完成之前找到的每个唯一索引屏蔽线程来更有效地执行它。

这当然有效,但如果你乘以非均匀情况,你将以非常不理想的着色器结束。要改善这一点,唯一的方法是不使用内在的并保证索引在波浪中是均匀的。例如,在 ExecuteIndirect 中将不同的材质拆分为单独的绘制调用。