问题描述
在Radeon HD 7750上运行并在thisMaterialsource
上声明(A)
时,该程序崩溃或冻结了PC,直到重新启动机器为止。在位置(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,spec);
ambientSum += ambient;
diffuseSum += diffuse;
specSum += spec;
}
}
else
{
for (int i=0; i<light.activeLights; ++i)
{
calculateLight(i,-inNormal.xyz,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,1) + emissive;
}
请原谅我的着色器代码的质量,我只是一起进行实验和研究,并且遇到了这个问题,除了烦人调试之外,这完全使我蒙蔽了眼睛。
它现在已修复,但是我想知道为什么会这样并且老实说,与我在学习中处理过的许多其他问题不同,我什至不知道从哪里开始寻找。
这仅仅是GPU /驱动程序中的错误还是表明着色器如何工作的一些深刻而神秘的欺骗的表现?如何调试此类问题?除了运行它之外,是否有其他方法可以看到它将会失败?我真的很想知道,我非常关心从中学习,而不仅仅是运行它。
解决方法
如果您不介意经历一个或两个以上的电源关闭周期,请尝试对着色器进行以下简化:
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显然要强大得多,并且不会遭受像这样的“滥用”。
除此之外,着色器应该没问题,并且上面的更改仍然是一种解决方法,而不是必须的。即使在更新的Radeons上,我们也遇到了GLSL的奇怪行为(即,某些行为与规范不符),但这与您的问题不相似。