在我的片段着色器中移动一个变量会导致它无法工作或使我的 PC 完全崩溃

Moving a variable in my fragment shader makes it either not work or completely crash my PC

当 运行 在 Radeon HD 7750 上运行并在 (A) 上声明 thisMaterialsource 时,程序要么崩溃,要么死机,以至于我不得不重启机器。当它在 (B) 位置声明时它工作正常。 运行在 Geforce GTX 1070 上运行时,两种情况下都可以正常工作。

void main()
{
    vec3 ambientSum = vec3(0);
    vec3 diffuseSum = vec3(0);
    vec3 specSum = vec3(0);
    vec3 ambient, diffuse, spec;

    // (A) - doesn't work when declared/set here  <----------------------------------------
    // Material thisMaterialsource = materialBanks[0].bank.materials[materialId];

    if (gl_FrontFacing)
    {
        for (int i=0; i<light.activeLights; ++i)
        {
            calculateLight(i, inWorldPos.xyz, inNormal.xyz, ambient, diffuse, spec);
            ambientSum += ambient;
            diffuseSum += diffuse;
            specSum += spec;
        }
    }
    else
    {
        for (int i=0; i<light.activeLights; ++i)
        {
            calculateLight(i, inWorldPos.xyz, -inNormal.xyz, ambient, diffuse, spec);
            ambientSum += ambient;
            diffuseSum += diffuse;
            specSum += spec;
        }
    }
    ambientSum /= light.activeLights;

    // (B) - works when declared/set here <----------------------------------------
    Material thisMaterialsource = materialBanks[0].bank.materials[materialId];

    vec4 texColor = thisMaterialsource.baseColorFactor;
    if(thisMaterialsource.colorTextureIndex > -1){ texColor = texture(texSampler[thisMaterialsource.colorTextureIndex], inUV0)  * thisMaterialsource.baseColorFactor; }

    vec4 emissive = thisMaterialsource.emissiveFactor;
    if (thisMaterialsource.unlitTextureIndex > -1) {
        emissive = texture(texSampler[thisMaterialsource.unlitTextureIndex], inUV0) * thisMaterialsource.emissiveFactor;
    }

    outColor = vec4(ambientSum + diffuseSum, 1) * texColor + vec4(specSum, 1) + emissive;
} 

完整着色器代码:

#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_EXT_nonuniform_qualifier : require

struct LightInfo
{
    vec3 Position;//Light Position in eye-coords
    vec3 La;//Ambient light intensity
    vec3 Ld;//Diffuse light intensity
    vec3 Ls;//Specular light intensity
};

struct MaterialInfo
{
    vec3 Ka;//Ambient reflectivity
    vec3 Kd;//Diffuse reflectivity
    vec3 Ks;//Specular reflectivity
    float Shininess;//Specular shininess factor
};

struct Material{
    vec4 baseColorFactor;
    vec4 emissiveFactor;
    float metallicFactor;
    float roughnessFactor;
    float normalScale;
    float occlusionStrength;

    int colorTextureIndex;
    int normalTextureIndex;
    int unlitTextureIndex;
    int ambientOcclusionTextureIndex;
    int metallicRoughnessTextureIndex;

    int isTwoSided;
    int alphaMode;
    float alphaCutoff;
};

struct MaterialBank{
    Material materials[80];
};

struct LightData{
    vec4 pos;
    vec4 color;
};


#define MAX_CAMERAS 16

struct CameraData{
    vec4 pos;
    mat4 mat;

    mat4 view;
    mat4 proj;
    mat4 clip;
};

layout(push_constant) uniform PushConsts {
    uint cameraIndex;
    uint time;
} pushConsts;

layout(binding = 0) uniform UniformBufferCamera {
    CameraData cameras[MAX_CAMERAS];
    uint cameraCount;
    uint cameraMax;
} cam;

layout(binding = 1) uniform UniformBufferLight {
    LightData lights[16];

    vec4 ambientColor;

    int activeLights;
} light;

layout(set=1, binding = 0) uniform sampler2D texSampler[32];
layout(set=2, binding = 0) uniform UniformBufferMat {
    MaterialBank bank;
} materialBanks[1];

layout(location = 0) in vec4 inNormal;
layout(location = 1) in vec2 inUV0;
layout(location = 2) in vec2 inUV1;
layout(location = 3) in vec4 inWorldPos;
layout(location = 4) in flat uint materialId;

layout(location = 0) out vec4 outColor;

void calculateLight(int lightIndex, vec3 position, vec3 norm, out vec3 ambient, out vec3 diffuse, out vec3 spec)
{
    LightData thisLightSource = light.lights[lightIndex];
    Material thisMaterialsource = materialBanks[0].bank.materials[materialId];

    LightInfo thisLight;
    thisLight.Position = thisLightSource.pos.xyz;//Light Position in eye-coords
    thisLight.La = light.ambientColor.rgb;//Ambient light intensity
    thisLight.Ld = thisLightSource.color.rgb;//Diffuse light intensity
    thisLight.Ls = thisLightSource.color.rgb;//Specular light intensity

    MaterialInfo thisMaterial;

    vec4 texColor = thisMaterialsource.baseColorFactor;
    if (thisMaterialsource.colorTextureIndex > -1){ texColor = texture(texSampler[thisMaterialsource.colorTextureIndex], inUV0) * thisMaterialsource.baseColorFactor; }

    vec4 mrSample = vec4(1);
    if (thisMaterialsource.metallicRoughnessTextureIndex > -1) { mrSample = texture(texSampler[thisMaterialsource.metallicRoughnessTextureIndex], inUV0); }

    float perceptualRoughness = mrSample.g * thisMaterialsource.roughnessFactor;
    float metallic = mrSample.b * thisMaterialsource.metallicFactor;

    thisMaterial.Ka= texColor.rgb * (metallic+perceptualRoughness)/2;//Ambient reflectivity
    thisMaterial.Kd= texColor.rgb * (perceptualRoughness);//Diffuse reflectivity
    thisMaterial.Ks= texColor.rgb * (metallic-perceptualRoughness);//Specular reflectivity
    thisMaterial.Shininess= (metallic);//Specular shininess factor

    vec3 n = normalize(norm);
    vec3 s = normalize(thisLight.Position - position);
    vec3 v = normalize(-position);
    vec3 r = reflect(-s, n);

    ambient = thisLight.La * thisMaterial.Ka;

    if (thisMaterialsource.ambientOcclusionTextureIndex > -1){
        float ao = texture(texSampler[thisMaterialsource.ambientOcclusionTextureIndex], inUV0).r;
        ambient = ambient * ao;
    }

    float sDotN = max(dot(s, n), 0.0);
    diffuse = thisLight.Ld * thisMaterial.Kd * sDotN;

    spec = thisLight.Ls * thisMaterial.Ks * pow(max(dot(r, v), 0.0), thisMaterial.Shininess);
}

void main()
{
    vec3 ambientSum = vec3(0);
    vec3 diffuseSum = vec3(0);
    vec3 specSum = vec3(0);
    vec3 ambient, diffuse, spec;

    // (A) - doesn't work when declared/set here  <----------------------------------------
    // Material thisMaterialsource = materialBanks[0].bank.materials[materialId];

    if (gl_FrontFacing)
    {
        for (int i=0; i<light.activeLights; ++i)
        {
            calculateLight(i, inWorldPos.xyz, inNormal.xyz, ambient, diffuse, spec);
            ambientSum += ambient;
            diffuseSum += diffuse;
            specSum += spec;
        }
    }
    else
    {
        for (int i=0; i<light.activeLights; ++i)
        {
            calculateLight(i, inWorldPos.xyz, -inNormal.xyz, ambient, diffuse, spec);
            ambientSum += ambient;
            diffuseSum += diffuse;
            specSum += spec;
        }
    }
    ambientSum /= light.activeLights;

    // (B) - works when declared/set here <----------------------------------------
    Material thisMaterialsource = materialBanks[0].bank.materials[materialId];

    vec4 texColor = thisMaterialsource.baseColorFactor;
    if(thisMaterialsource.colorTextureIndex > -1){ texColor = texture(texSampler[thisMaterialsource.colorTextureIndex], inUV0)  * thisMaterialsource.baseColorFactor; }

    vec4 emissive = thisMaterialsource.emissiveFactor;
    if (thisMaterialsource.unlitTextureIndex > -1) {
        emissive = texture(texSampler[thisMaterialsource.unlitTextureIndex], inUV0) * thisMaterialsource.emissiveFactor;
    }

    outColor = vec4(ambientSum + diffuseSum, 1) * texColor + vec4(specSum, 1) + emissive;
} 

请原谅我的着色器代码的质量问题,我只是在试验和拼凑东西,然后遇到了这个问题,除了烦人的调试之外,完全让我措手不及。

它现在已修复,但我想知道它为什么会发生,老实说,与我在学习过程中处理过的许多其他问题不同,我什至不知道从哪里开始寻找。

这仅仅是 GPU/drivers 中的一个错误,还是决定着色器如何工作的一些深刻而神秘的阴谋的表现?我该如何调试这类问题?除了 运行ning 之外,有没有办法看出这会失败?我真的很想知道,我更关心从中学习,而不是仅仅达到 运行。

如果您不介意再经历一两个 power-off-on 周期,请尝试对着色器进行以下简化:

void main()
{
    ... variables

    // (A) - doesn't work when declared/set here  <----------------------------------------
    // Material thisMaterialsource = materialBanks[0].bank.materials[materialId];

    /// Instead of doing two almost identical loops, extract the normal inversion
    vec3 normal = (gl_FrontFacing ? inNormal : -inNormal).xyz;
    for (int i=0; i<light.activeLights; ++i)
    {
        calculateLight(i, inWorldPos.xyz, normal, ambient, diffuse, spec);
        ambientSum += ambient;
        diffuseSum += diffuse;
        specSum += spec;
    }
    ambientSum /= light.activeLights;

    // (B) - works when declared/set here <----------------------------------------
    Material thisMaterialsource = materialBanks[0].bank.materials[materialId];

    ... all the rest
} 

一个疯狂的猜测可能如下:HD7750 相对较旧,如果 GLSL 编译器做了一些奇怪的事情,活动灯的两个循环(动态数量)会生成过多的着色器字节码。所以你会得到可用线程内存的溢出。 GTX 1070显然更强大,不会遭受这样的“虐待”。

除此之外,着色器应该没问题,上述更改仍然是一种解决方法,不是必须的。即使在较新的 Radeon 上,我们也遇到过 GLSL 的奇怪行为(即,有些事情不符合规范),但这与您的问题不相似。